aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMaxime Devos <maximedevos@telenet.be>2021-08-12 16:04:44 +0200
committerMaxime Devos <maximedevos@telenet.be>2021-09-21 12:13:35 +0200
commitcb3cd67b31a03d2acb40c7d64528865a69f46ab8 (patch)
tree148c7963b0f7f5cbb348c6b48387f7451966a68e /tests
parentdf373e2ad6d2fd5bdde80921082c8c4ea1d69094 (diff)
downloadgnunet-scheme-cb3cd67b31a03d2acb40c7d64528865a69f46ab8.tar.gz
gnunet-scheme-cb3cd67b31a03d2acb40c7d64528865a69f46ab8.zip
mq-impl/stream: Implement connecting to unix sockets.
* README.org (Message queues): Note existence of 'connect-unix'. (List of errors): Mention 'connection:connected'. * gnu/gnunet/mq-impl/stream.scm (%path-resolution-errors): New variable. (connect-unix): New procedure. (connect/fibers): New procedure. * tests/mq-stream.scm (call-with-temporary-directory) (make-config) (call-with-socket-location) (connect/test) (alist->hash-table) (test-connection) (yield-many): New procedures. ("connect-unix, can connect when socket is already listening") ("connect-unix, will connect when socket is listening") ("connect-unix, will connect when socket is bound (and listening)") ("connect-unix, will connect even if there's an old socket lying around") ("connect-unix, will connect even if previous socket is different type") ("connect-unix, will connect even if permissions are temporarily wrong"): New tests.
Diffstat (limited to 'tests')
-rw-r--r--tests/mq-stream.scm173
1 files changed, 172 insertions, 1 deletions
diff --git a/tests/mq-stream.scm b/tests/mq-stream.scm
index fa70a1d..1fce3f5 100644
--- a/tests/mq-stream.scm
+++ b/tests/mq-stream.scm
@@ -21,6 +21,7 @@
21 (gnu gnunet mq handler) 21 (gnu gnunet mq handler)
22 (gnu gnunet utils hat-let) 22 (gnu gnunet utils hat-let)
23 (gnu gnunet utils bv-slice) 23 (gnu gnunet utils bv-slice)
24 (gnu gnunet config db)
24 (gnu gnunet concurrency repeated-condition) 25 (gnu gnunet concurrency repeated-condition)
25 (fibers conditions) 26 (fibers conditions)
26 (fibers operations) 27 (fibers operations)
@@ -28,12 +29,15 @@
28 (rnrs bytevectors) 29 (rnrs bytevectors)
29 ((rnrs io ports) #:select (open-bytevector-input-port)) 30 ((rnrs io ports) #:select (open-bytevector-input-port))
30 ((rnrs base) #:select (assert)) 31 ((rnrs base) #:select (assert))
32 (rnrs hashtables)
31 (srfi srfi-26) 33 (srfi srfi-26)
32 (srfi srfi-43) 34 (srfi srfi-43)
33 (rnrs io ports) 35 (rnrs io ports)
34 (ice-9 binary-ports) 36 (ice-9 binary-ports)
35 (ice-9 suspendable-ports) 37 (ice-9 suspendable-ports)
36 (ice-9 control)) 38 (ice-9 control)
39 (ice-9 match)
40 (ice-9 threads))
37 41
38(define (no-sender . _) 42(define (no-sender . _)
39 (error "no sender!")) 43 (error "no sender!"))
@@ -231,4 +235,171 @@
231 #:parallelism 1 235 #:parallelism 1
232 #:hz 0))) 236 #:hz 0)))
233 237
238(define (call-with-temporary-directory proc)
239 (let ((file (mkdtemp (in-vicinity (or (getenv "TMPDIR") "/tmp")
240 "test-XXXXXX"))))
241 (with-exception-handler
242 (lambda (e)
243 (system* "rm" "-r" file)
244 (raise-exception e))
245 (lambda ()
246 (call-with-values
247 (lambda () (proc file))
248 (lambda the-values
249 (system* "rm" "-r" file)
250 (apply values the-values)))))))
251
252(define (make-config where)
253 (hash->configuration
254 (alist->hash-table
255 `((("service" . "UNIXPATH") . ,where)))))
256
257(define (call-with-socket-location proc)
258 (call-with-temporary-directory
259 (lambda (dir)
260 (define where (in-vicinity dir "sock.et"))
261 (define config (make-config where))
262 (proc where config))))
263
264(define (connect/test config connected?)
265 (define (error-handler . error)
266 (match error
267 ;; XXX correct documentation: multiple end-of-files
268 ;; are perfectly possible.
269 (('input:regular-end-of-file) (values))
270 (('connection:connected) (signal-condition! connected?))))
271 (connect/fibers config "service" no-handlers error-handler
272 #:spawn call-with-new-thread))
273
274(define (alist->hash-table alist)
275 (define h (make-hashtable (lambda (key) 0) equal?))
276 (define (insert! key+value)
277 (hashtable-set! h (car key+value) (cdr key+value)))
278 (for-each insert! alist)
279 h)
280
281(define (test-connection mq server-sock)
282 (send-message! mq (bv-slice/read-write #vu8(0 4 0 0)))
283 (let ((client (car (accept server-sock))))
284 (assert (equal? #vu8(0 4 0 0) (get-bytevector-n client 4)))
285 #t))
286
287(define (yield-many)
288 ;; Give the new threads some time to run before binding the socket.
289 ;; This allowed a bug in the use of 'connect' to be detected.
290 (let loop ((n (* 8 (+ 1 (length (all-threads))))))
291 (when (> n 0)
292 (yield)
293 (loop (- n 1)))))
294
295(test-assert "connect-unix, can connect when socket is already listening"
296 (call-with-socket-location
297 (lambda (where config)
298 (define listening-sock (socket PF_UNIX SOCK_STREAM 0))
299 (define connected? (make-condition))
300 (bind listening-sock AF_UNIX where)
301 (listen listening-sock 1)
302 (define mq (connect/test config connected?))
303 (wait connected?)
304 (test-connection mq listening-sock))))
305
306;; Consider the case where a service starts, has bound its socket
307;; but is not yet listening, and a client connects.
308(test-assert "connect-unix, will connect when socket is listening"
309 (call-with-socket-location
310 (lambda (where config)
311 (define listening-sock (socket PF_UNIX SOCK_STREAM 0))
312 (define connected? (make-condition))
313 (bind listening-sock AF_UNIX where)
314 (define mq (connect/test config connected?))
315 (yield-many)
316 (listen listening-sock 1)
317 (wait connected?)
318 (test-connection mq listening-sock))))
319
320;; Consider the case where a client starts before a service.
321(test-assert "connect-unix, will connect when socket is bound (and listening)"
322 (call-with-socket-location
323 (lambda (where config)
324 (define listening-sock (socket PF_UNIX SOCK_STREAM 0))
325 (define connected? (make-condition))
326 (define mq (connect/test config connected?))
327 (yield-many)
328 (bind listening-sock AF_UNIX where)
329 (listen listening-sock 1)
330 (wait connected?)
331 (test-connection mq listening-sock))))
332
333;; Consider the case where a service starts and stops,
334;; a client connects and the service restarts.
335(test-assert
336 "connect-unix, will connect even if there's an old socket lying around"
337 (call-with-socket-location
338 (lambda (where config)
339 (let ((old-sock (socket PF_UNIX SOCK_STREAM 0)))
340 (bind old-sock AF_UNIX where)
341 (close-port old-sock))
342 (define connected? (make-condition))
343 (define mq (connect/test config connected?))
344 (yield-many)
345 (define listening-sock (socket PF_UNIX SOCK_STREAM 0))
346 (yield-many)
347 ;; Delete the old socket, otherwise the 'bind' below results in ‘address alreay in use’
348 (delete-file where)
349 (yield-many)
350 (bind listening-sock AF_UNIX where)
351 (yield-many)
352 (listen listening-sock 1)
353 (wait connected?)
354 (test-connection mq listening-sock))))
355
356;; Consider the case where GNUnet version N uses stream sockets,
357;; GNUnet version M uses datagram sockets, the system initially
358;; uses GNUnet version N, a client for version M is started
359;; (initially failing to connect to the server), then the system
360;; switches to GNUnet version M.
361(test-assert
362 "connect-unix, will connect even if previous socket is different type"
363 (call-with-socket-location
364 (lambda (where config)
365 (define old-sock (socket PF_UNIX SOCK_DGRAM 0))
366 (bind old-sock AF_UNIX where)
367 ;; Datagram sockets don't support 'listen', so don't
368 ;; call 'listen' with 'old-sock'.
369 (define connected? (make-condition))
370 (define mq (connect/test config connected?))
371 (yield-many)
372 (close-port old-sock)
373 (delete-file where)
374 (define new-sock (socket PF_UNIX SOCK_STREAM 0))
375 (bind new-sock AF_UNIX where)
376 (listen new-sock 1)
377 (wait connected?)
378 (test-connection mq new-sock))))
379
380;; Consider a system that creates directories and the socket
381;; with world-unreadable, world-unexecutable permissions at
382;; first and makes the permissions more permissive later.
383(test-assert
384 "connect-unix, will connect even if permissions are temporarily wrong"
385 (call-with-temporary-directory
386 (lambda (tmpdir)
387 ;; Permissions on sockets can be unreliable on some systems,
388 ;; so modify the permissions of a directory instead.
389 (define subdir (in-vicinity tmpdir "dir"))
390 (mkdir subdir)
391 (define where (in-vicinity subdir "sock.et"))
392 (define listening-sock (socket PF_UNIX SOCK_STREAM 0))
393 (bind listening-sock AF_UNIX where)
394 (listen listening-sock 1)
395 (chmod subdir #o000) ; unreadable
396 (define connected? (make-condition))
397 (define mq (connect/test (make-config where) connected?))
398 (yield-many)
399 ;; make it readable again
400 ;; (and writable such that 'tmpdir' can be deleted).
401 (chmod subdir #o700)
402 (wait connected?)
403 (test-connection mq listening-sock))))
404
234(test-end "mq-stream") 405(test-end "mq-stream")