00-socket.test 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. ;;;; 00-socket.test --- test socket functions -*- scheme -*-
  2. ;;;;
  3. ;;;; Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010,
  4. ;;;; 2011, 2012, 2013, 2014, 2017, 2021 Free Software Foundation, Inc.
  5. ;;;;
  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.
  10. ;;;;
  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.
  15. ;;;;
  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
  19. ;; This test runs early, so that we can fork before any threads are
  20. ;; created in other tests.
  21. (define-module (test-suite test-socket)
  22. #:use-module (rnrs bytevectors)
  23. #:use-module (srfi srfi-26)
  24. #:use-module (test-suite lib))
  25. ;;;
  26. ;;; inet-ntop
  27. ;;;
  28. (if (defined? 'inet-ntop)
  29. (with-test-prefix "inet-ntop"
  30. (with-test-prefix "ipv6"
  31. (pass-if "0"
  32. (string? (inet-ntop AF_INET6 0)))
  33. (pass-if "2^128-1"
  34. (string? (inet-ntop AF_INET6 (1- (ash 1 128)))))
  35. (pass-if-exception "-1" exception:out-of-range
  36. (inet-ntop AF_INET6 -1))
  37. (pass-if-exception "2^128" exception:out-of-range
  38. (inet-ntop AF_INET6 (ash 1 128)))
  39. (pass-if-exception "2^1024" exception:out-of-range
  40. (inet-ntop AF_INET6 (ash 1 1024))))))
  41. ;;;
  42. ;;; inet-pton
  43. ;;;
  44. (if (defined? 'inet-pton)
  45. (with-test-prefix "inet-pton"
  46. (with-test-prefix "ipv6"
  47. (pass-if "00:00:00:00:00:00:00:00"
  48. (eqv? 0 (inet-pton AF_INET6 "00:00:00:00:00:00:00:00")))
  49. (pass-if "0:0:0:0:0:0:0:1"
  50. (eqv? 1 (inet-pton AF_INET6 "0:0:0:0:0:0:0:1")))
  51. (pass-if "::1"
  52. (eqv? 1 (inet-pton AF_INET6 "::1")))
  53. (pass-if "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
  54. (eqv? #xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
  55. (inet-pton AF_INET6
  56. "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF")))
  57. (pass-if "F000:0000:0000:0000:0000:0000:0000:0000"
  58. (eqv? #xF0000000000000000000000000000000
  59. (inet-pton AF_INET6
  60. "F000:0000:0000:0000:0000:0000:0000:0000")))
  61. (pass-if "0F00:0000:0000:0000:0000:0000:0000:0000"
  62. (eqv? #x0F000000000000000000000000000000
  63. (inet-pton AF_INET6
  64. "0F00:0000:0000:0000:0000:0000:0000:0000")))
  65. (pass-if "0000:0000:0000:0000:0000:0000:0000:00F0"
  66. (eqv? #xF0
  67. (inet-pton AF_INET6
  68. "0000:0000:0000:0000:0000:0000:0000:00F0"))))))
  69. (if (defined? 'inet-ntop)
  70. (with-test-prefix "inet-ntop"
  71. (with-test-prefix "ipv4"
  72. (pass-if "127.0.0.1"
  73. (equal? "127.0.0.1" (inet-ntop AF_INET INADDR_LOOPBACK))))
  74. (if (defined? 'AF_INET6)
  75. (with-test-prefix "ipv6"
  76. (pass-if "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
  77. (string-ci=? "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
  78. (inet-ntop AF_INET6 (- (expt 2 128) 1))))
  79. (pass-if "::1"
  80. (equal? "::1" (inet-ntop AF_INET6 1)))))))
  81. ;;;
  82. ;;; make-socket-address
  83. ;;;
  84. (with-test-prefix "make-socket-address"
  85. (if (defined? 'AF_INET)
  86. (pass-if "AF_INET"
  87. (let ((sa (make-socket-address AF_INET 123456 80)))
  88. (and (= (sockaddr:fam sa) AF_INET)
  89. (= (sockaddr:addr sa) 123456)
  90. (= (sockaddr:port sa) 80)))))
  91. (if (defined? 'AF_INET6)
  92. (pass-if "AF_INET6"
  93. ;; Since the platform doesn't necessarily support `scopeid', we won't
  94. ;; test it.
  95. (let ((sa* (make-socket-address AF_INET6 123456 80 1))
  96. (sa+ (make-socket-address AF_INET6 123456 80)))
  97. (and (= (sockaddr:fam sa*) (sockaddr:fam sa+) AF_INET6)
  98. (= (sockaddr:addr sa*) (sockaddr:addr sa+) 123456)
  99. (= (sockaddr:port sa*) (sockaddr:port sa+) 80)
  100. (= (sockaddr:flowinfo sa*) 1)))))
  101. (if (defined? 'AF_UNIX)
  102. (begin
  103. (pass-if "AF_UNIX"
  104. (let ((sa (make-socket-address AF_UNIX "/tmp/unix-socket")))
  105. (and (= (sockaddr:fam sa) AF_UNIX)
  106. (string=? (sockaddr:path sa) "/tmp/unix-socket"))))
  107. (pass-if "AF_UNIX abstract"
  108. (let ((sa (make-socket-address AF_UNIX "\x00/tmp/abstract-socket")))
  109. (and (= (sockaddr:fam sa) AF_UNIX)
  110. (string=? (sockaddr:path sa) "\x00/tmp/abstract-socket")))))))
  111. ;;;
  112. ;;; setsockopt
  113. ;;;
  114. (with-test-prefix "setsockopt AF_INET"
  115. (if (and (defined? 'AF_INET) (defined? 'TCP_NODELAY))
  116. (pass-if "IPPROTO_TCP TCP_NODELAY"
  117. (let ((sock (socket AF_INET SOCK_STREAM 0)))
  118. (setsockopt sock IPPROTO_TCP TCP_NODELAY 1)
  119. (eqv? 1 (getsockopt sock IPPROTO_TCP TCP_NODELAY))))))
  120. ;;;
  121. ;;; AF_UNIX sockets and `make-socket-address'
  122. ;;;
  123. (define %tmpdir
  124. ;; Honor `$TMPDIR', which tmpnam(3) doesn't do.
  125. (or (getenv "TMPDIR") "/tmp"))
  126. (define %curdir
  127. ;; Remember the current working directory.
  128. (getcwd))
  129. ;; Temporarily cd to %TMPDIR. The goal is to work around path name
  130. ;; limitations, which can lead to exceptions like:
  131. ;;
  132. ;; (misc-error "scm_to_sockaddr"
  133. ;; "unix address path too long: ~A"
  134. ;; ("/tmp/nix-build-fb7bph4ifh0vr3ihigm702dzffdnapfj-guile-coverage-1.9.5.drv-0/guile-test-socket-1258553296-77619")
  135. ;; #f)
  136. (false-if-exception (chdir %tmpdir))
  137. (define (temp-file-path)
  138. ;; Return a temporary file name, assuming the current directory is %TMPDIR.
  139. (string-append "guile-test-socket-"
  140. (number->string (current-time)) "-"
  141. (number->string (random 100000))))
  142. (define (primitive-fork-if-available)
  143. (if (not (provided? 'fork))
  144. -1
  145. (primitive-fork)))
  146. (if (defined? 'AF_UNIX)
  147. (with-test-prefix "AF_UNIX/SOCK_DGRAM"
  148. ;; testing `bind' and `sendto' and datagram sockets
  149. (let ((server-socket (socket AF_UNIX SOCK_DGRAM 0))
  150. (server-bound? #f)
  151. (path (temp-file-path)))
  152. (pass-if "bind"
  153. (catch 'system-error
  154. (lambda ()
  155. (bind server-socket AF_UNIX path)
  156. (set! server-bound? #t)
  157. #t)
  158. (lambda args
  159. (let ((errno (system-error-errno args)))
  160. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  161. (else (apply throw args)))))))
  162. (pass-if "bind/sockaddr"
  163. (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
  164. (path (temp-file-path))
  165. (sockaddr (make-socket-address AF_UNIX path)))
  166. (catch 'system-error
  167. (lambda ()
  168. (bind sock sockaddr)
  169. (false-if-exception (delete-file path))
  170. #t)
  171. (lambda args
  172. (let ((errno (system-error-errno args)))
  173. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  174. (else (apply throw args))))))))
  175. (pass-if "sendto"
  176. (if (not server-bound?)
  177. (throw 'unresolved)
  178. (let ((client (socket AF_UNIX SOCK_DGRAM 0))
  179. (message (string->utf8 "hello")))
  180. (> (sendto client message AF_UNIX path) 0))))
  181. (pass-if "sendto/sockaddr"
  182. (if (not server-bound?)
  183. (throw 'unresolved)
  184. (let ((client (socket AF_UNIX SOCK_DGRAM 0))
  185. (message (string->utf8 "hello"))
  186. (sockaddr (make-socket-address AF_UNIX path)))
  187. (> (sendto client message sockaddr) 0))))
  188. (false-if-exception (delete-file path)))))
  189. (if (defined? 'AF_UNIX)
  190. (with-test-prefix "AF_UNIX/SOCK_STREAM"
  191. ;; testing `bind', `listen' and `connect' on stream-oriented sockets
  192. (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
  193. (server-bound? #f)
  194. (server-listening? #f)
  195. (server-pid #f)
  196. (path (temp-file-path)))
  197. (pass-if "bind"
  198. (catch 'system-error
  199. (lambda ()
  200. (bind server-socket AF_UNIX path)
  201. (set! server-bound? #t)
  202. #t)
  203. (lambda args
  204. (let ((errno (system-error-errno args)))
  205. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  206. (else (apply throw args)))))))
  207. (pass-if "bind/sockaddr"
  208. (let* ((sock (socket AF_UNIX SOCK_STREAM 0))
  209. (path (temp-file-path))
  210. (sockaddr (make-socket-address AF_UNIX path)))
  211. (catch 'system-error
  212. (lambda ()
  213. (bind sock sockaddr)
  214. (false-if-exception (delete-file path))
  215. #t)
  216. (lambda args
  217. (let ((errno (system-error-errno args)))
  218. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  219. (else (apply throw args))))))))
  220. (pass-if "listen"
  221. (if (not server-bound?)
  222. (throw 'unresolved)
  223. (begin
  224. (listen server-socket 123)
  225. (set! server-listening? #t)
  226. #t)))
  227. (force-output (current-output-port))
  228. (force-output (current-error-port))
  229. (when server-listening?
  230. (let ((pid (primitive-fork-if-available)))
  231. ;; Spawn a server process.
  232. (case pid
  233. ((-1) ;; fork not available
  234. #f)
  235. ((0) ;; the kid: serve two connections and exit
  236. (let serve ((conn
  237. (false-if-exception (accept server-socket)))
  238. (count 1))
  239. (if (not conn)
  240. (exit 1)
  241. (if (> count 0)
  242. (serve (false-if-exception (accept server-socket))
  243. (- count 1)))))
  244. (exit 0))
  245. (else ;; the parent
  246. (set! server-pid pid)
  247. #t))))
  248. (pass-if "connect"
  249. (if (not server-pid)
  250. (throw 'unresolved)
  251. (let ((s (socket AF_UNIX SOCK_STREAM 0)))
  252. (connect s AF_UNIX path)
  253. #t)))
  254. (pass-if "connect/sockaddr"
  255. (if (not server-pid)
  256. (throw 'unresolved)
  257. (let ((s (socket AF_UNIX SOCK_STREAM 0)))
  258. (connect s (make-socket-address AF_UNIX path))
  259. #t)))
  260. (pass-if "accept"
  261. (if (not server-pid)
  262. (throw 'unresolved)
  263. (let ((status (cdr (waitpid server-pid))))
  264. (eqv? 0 (status:exit-val status)))))
  265. (false-if-exception (delete-file path))
  266. #t)
  267. ;; testing `bind', `listen' and `connect' on abstract stream-oriented sockets
  268. (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
  269. (server-bound? #f)
  270. (server-listening? #f)
  271. (server-pid #f)
  272. (path (temp-file-path)))
  273. (false-if-exception (delete-file path))
  274. (set! path (string-append "\x00" path))
  275. (pass-if "bind abstract"
  276. (catch 'system-error
  277. (lambda ()
  278. (bind server-socket AF_UNIX path)
  279. (set! server-bound? #t)
  280. #t)
  281. (lambda args
  282. (let ((errno (system-error-errno args)))
  283. (if (= errno EADDRINUSE)
  284. (throw 'unresolved)
  285. (apply throw args))))))
  286. (pass-if "listen abstract"
  287. (if (not server-bound?)
  288. (throw 'unresolved)
  289. (begin
  290. (listen server-socket 123)
  291. (set! server-listening? #t)
  292. #t)))
  293. (force-output (current-output-port))
  294. (force-output (current-error-port))
  295. (when server-listening?
  296. (let ((pid (primitive-fork-if-available)))
  297. ;; Spawn a server process.
  298. (case pid
  299. ((-1) ;; fork not available
  300. #f)
  301. ((0) ;; the kid: serve one connection and exit
  302. (let serve ((conn
  303. (false-if-exception (accept server-socket)))
  304. (count 0))
  305. (if (not conn)
  306. (exit 1)
  307. (exit 0))))
  308. (else ;; the parent
  309. (set! server-pid pid)
  310. #t))))
  311. (pass-if "connect abstract"
  312. (if (not server-pid)
  313. (throw 'unresolved)
  314. (let ((s (socket AF_UNIX SOCK_STREAM 0)))
  315. (display "connect abstract\n")
  316. (connect s AF_UNIX path)
  317. #t)))
  318. (pass-if "accept abstract"
  319. (if (not server-pid)
  320. (throw 'unresolved)
  321. (begin
  322. (let ((status (cdr (waitpid server-pid))))
  323. (eqv? 0 (status:exit-val status))))))
  324. #t)
  325. ;; Testing `send', `recv!' & co. on stream-oriented sockets (with
  326. ;; a bit of duplication with the above.)
  327. (let ((server-socket (socket AF_UNIX SOCK_STREAM 0))
  328. (server-bound? #f)
  329. (server-listening? #f)
  330. (server-pid #f)
  331. (message "hello, world!")
  332. (path (temp-file-path)))
  333. (define (sub-bytevector bv len)
  334. (let ((c (make-bytevector len)))
  335. (bytevector-copy! bv 0 c 0 len)
  336. c))
  337. (pass-if "bind (bis)"
  338. (catch 'system-error
  339. (lambda ()
  340. (bind server-socket AF_UNIX path)
  341. (set! server-bound? #t)
  342. #t)
  343. (lambda args
  344. (let ((errno (system-error-errno args)))
  345. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  346. (else (apply throw args)))))))
  347. (pass-if "listen (bis)"
  348. (if (not server-bound?)
  349. (throw 'unresolved)
  350. (begin
  351. (listen server-socket 123)
  352. (set! server-listening? #t)
  353. #t)))
  354. (force-output (current-output-port))
  355. (force-output (current-error-port))
  356. (if server-listening?
  357. (let ((pid (primitive-fork-if-available)))
  358. ;; Spawn a server process.
  359. (case pid
  360. ((-1)
  361. #f)
  362. ((0) ;; the kid: send MESSAGE and exit
  363. (exit
  364. (false-if-exception
  365. (let ((conn (car (accept server-socket)))
  366. (bv (string->utf8 message)))
  367. (= (bytevector-length bv)
  368. (send conn bv))))))
  369. (else ;; the parent
  370. (set! server-pid pid)
  371. #t))))
  372. (pass-if "recv!"
  373. (if (not server-pid)
  374. (throw 'unresolved)
  375. (let ((s (socket AF_UNIX SOCK_STREAM 0)))
  376. (connect s AF_UNIX path)
  377. (let* ((buf (make-bytevector 123))
  378. (received (recv! s buf)))
  379. (string=? (utf8->string (sub-bytevector buf received))
  380. message)))))
  381. (pass-if "accept (bis)"
  382. (if (not server-pid)
  383. (throw 'unresolved)
  384. (let ((status (cdr (waitpid server-pid))))
  385. (eqv? 0 (status:exit-val status)))))
  386. (false-if-exception (delete-file path))
  387. #t)))
  388. (if (defined? 'AF_INET6)
  389. (with-test-prefix "AF_INET6/SOCK_STREAM"
  390. ;; testing `bind', `listen' and `connect' on stream-oriented sockets
  391. (let ((server-socket
  392. ;; Some platforms don't support this protocol/family combination.
  393. (false-if-exception (socket AF_INET6 SOCK_STREAM 0)))
  394. (server-bound? #f)
  395. (server-listening? #f)
  396. (server-pid #f)
  397. (ipv6-addr 1) ; ::1
  398. (server-port 8889)
  399. (client-port 9998))
  400. (pass-if "bind"
  401. (if (not server-socket)
  402. (throw 'unresolved))
  403. (catch 'system-error
  404. (lambda ()
  405. (bind server-socket AF_INET6 ipv6-addr server-port)
  406. (set! server-bound? #t)
  407. #t)
  408. (lambda args
  409. (let ((errno (system-error-errno args)))
  410. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  411. ;; On Linux-based systems, when `ipv6' support is
  412. ;; missing (for instance, `ipv6' is loaded and
  413. ;; /proc/sys/net/ipv6/conf/all/disable_ipv6 is set
  414. ;; to 1), the socket call above succeeds but
  415. ;; bind(2) fails like this.
  416. ((= errno EADDRNOTAVAIL) (throw 'unresolved))
  417. (else (apply throw args)))))))
  418. (pass-if "bind/sockaddr"
  419. (let* ((sock (false-if-exception (socket AF_INET6 SOCK_STREAM 0)))
  420. (sockaddr (make-socket-address AF_INET6 ipv6-addr client-port)))
  421. (if (not sock)
  422. (throw 'unresolved))
  423. (catch 'system-error
  424. (lambda ()
  425. (bind sock sockaddr)
  426. #t)
  427. (lambda args
  428. (let ((errno (system-error-errno args)))
  429. (cond ((= errno EADDRINUSE) (throw 'unresolved))
  430. ((= errno EADDRNOTAVAIL) (throw 'unresolved))
  431. (else (apply throw args))))))))
  432. (pass-if "listen"
  433. (if (not server-bound?)
  434. (throw 'unresolved)
  435. (begin
  436. (listen server-socket 123)
  437. (set! server-listening? #t)
  438. #t)))
  439. (force-output (current-output-port))
  440. (force-output (current-error-port))
  441. (if server-listening?
  442. (let ((pid (primitive-fork-if-available)))
  443. ;; Spawn a server process.
  444. (case pid
  445. ((-1)
  446. #f)
  447. ((0) ;; the kid: serve two connections and exit
  448. (let serve ((conn
  449. (false-if-exception (accept server-socket)))
  450. (count 1))
  451. (if (not conn)
  452. (exit 1)
  453. (if (> count 0)
  454. (serve (false-if-exception (accept server-socket))
  455. (- count 1)))))
  456. (exit 0))
  457. (else ;; the parent
  458. (set! server-pid pid)
  459. #t))))
  460. (pass-if "connect"
  461. (if (not server-pid)
  462. (throw 'unresolved)
  463. (let ((s (socket AF_INET6 SOCK_STREAM 0)))
  464. (connect s AF_INET6 ipv6-addr server-port)
  465. #t)))
  466. (pass-if "connect/sockaddr"
  467. (if (not server-pid)
  468. (throw 'unresolved)
  469. (let ((s (socket AF_INET6 SOCK_STREAM 0)))
  470. (connect s (make-socket-address AF_INET6 ipv6-addr server-port))
  471. #t)))
  472. (pass-if "accept"
  473. (if (not server-pid)
  474. (throw 'unresolved)
  475. (let ((status (cdr (waitpid server-pid))))
  476. (eqv? 0 (status:exit-val status)))))
  477. #t)))
  478. ;; Switch back to the previous directory.
  479. (false-if-exception (chdir %curdir))