X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=contrib%2Fsb-bsd-sockets%2Ftests.lisp;h=95fcf43ae8ec4579fc04718fb2be34c52ed31c24;hb=2d68a49fe9d30f687da45cfe7a02b497cb91137c;hp=1ed052fd574ef86566bbcf9a4009b9822a9ab303;hpb=f79e7df41edd15a68c763263a81e7c640005a60b;p=sbcl.git diff --git a/contrib/sb-bsd-sockets/tests.lisp b/contrib/sb-bsd-sockets/tests.lisp index 1ed052f..95fcf43 100644 --- a/contrib/sb-bsd-sockets/tests.lisp +++ b/contrib/sb-bsd-sockets/tests.lisp @@ -89,35 +89,24 @@ (non-blocking-mode s)) t) -(defun do-gc-portably () - ;; cmucl on linux has generational gc with a keyword argument, - ;; sbcl GC function takes same arguments no matter what collector is in - ;; use - #+(or sbcl gencgc) (SB-EXT:gc :full t) - ;; other platforms have full gc or nothing - #-(or sbcl gencgc) (sb-ext:gc)) - (deftest inet-socket-bind (let* ((tcp (get-protocol-by-name "tcp")) (address (make-inet-address "127.0.0.1")) - (s (make-instance 'inet-socket :type :stream :protocol tcp))) - (do-gc-portably) ; gc should clear out any old sockets bound to this port + (s1 (make-instance 'inet-socket :type :stream :protocol tcp)) + (s2 (make-instance 'inet-socket :type :stream :protocol tcp))) (unwind-protect ;; Given the functions we've got so far, if you can think of a ;; better way to make sure the bind succeeded than trying it ;; twice, let me know (progn - (socket-bind s address 0) + (socket-bind s1 address 0) (handler-case - (let ((port (nth-value 1 (socket-name s))) - (s2 (make-instance 'inet-socket - :type :stream :protocol tcp))) - (unwind-protect - (socket-bind s2 address port) - (socket-close s2)) + (let ((port (nth-value 1 (socket-name s1)))) + (socket-bind s2 address port) nil) (address-in-use-error () t))) - (socket-close s))) + (socket-close s1) + (socket-close s2))) t) (deftest* (simple-sockopt-test) @@ -373,3 +362,63 @@ (server)) result) :ok) + +(defmacro with-client-and-server ((server-socket-var client-socket-var) &body body) + (let ((listen-socket (gensym "LISTEN-SOCKET"))) + `(let ((,listen-socket (make-instance 'inet-socket + :type :stream + :protocol :tcp)) + (,client-socket-var (make-instance 'inet-socket + :type :stream + :protocol :tcp)) + (,server-socket-var)) + (unwind-protect + (progn + (setf (sockopt-reuse-address ,listen-socket) t) + (socket-bind ,listen-socket (make-inet-address "127.0.0.1") 0) + (socket-listen ,listen-socket 5) + (socket-connect ,client-socket-var (make-inet-address "127.0.0.1") + (nth-value 1 (socket-name ,listen-socket))) + (setf ,server-socket-var (socket-accept ,listen-socket)) + ,@body) + (socket-close ,client-socket-var) + (socket-close ,listen-socket) + (when ,server-socket-var + (socket-close ,server-socket-var)))))) + +;; For stream sockets, make sure a shutdown of the output direction +;; translates into an END-OF-FILE on the other end, no matter which +;; end performs the shutdown and independent of the element-type of +;; the stream. +(macrolet + ((define-shutdown-test (name who-shuts-down who-reads element-type direction) + `(deftest ,name + (with-client-and-server (client server) + (socket-shutdown ,who-shuts-down :direction ,direction) + (handler-case + (sb-ext:with-timeout 2 + (,(if (eql element-type 'character) + 'read-char 'read-byte) + (socket-make-stream + ,who-reads :input t :output t + :element-type ',element-type))) + (end-of-file () + :ok) + (sb-ext:timeout () :timeout))) + :ok)) + (define-shutdown-tests (direction) + (flet ((make-name (name) + (intern (concatenate + 'string (string name) "." (string direction))))) + `(progn + (define-shutdown-test ,(make-name 'shutdown.server.character) + server client character ,direction) + (define-shutdown-test ,(make-name 'shutdown.server.ub8) + server client (unsigned-byte 8) ,direction) + (define-shutdown-test ,(make-name 'shutdown.client.character) + client server character ,direction) + (define-shutdown-test ,(make-name 'shutdown.client.ub8) + client server (unsigned-byte 8) ,direction))))) + + (define-shutdown-tests :output) + (define-shutdown-tests :io))