;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*- ;;; Patch file for System version 123.91 ;;; Reason: ;;; The :listen method for an tcp-stream (actually, for a buffered stream, the no-hang ;;; version of :next-input-buffer) ends up calling :handle-all-replies, which can ;;; throw you into the error handler if it detects a send-timeout. If you are using ;;; the :listen in a process-wait function, you get an error in the scheduler, which ;;; is fatal. The solution is to detect the timeout in :handle-reply, and for the ;;; listen method to return T if a timeout occurs, but don't enter the error handler ;;; until a blocking method (:next-input-buffer or :tyi) is called. ;;; Written 3-Nov-87 15:08:45 by pld at site LMI Cambridge ;;; while running on Jack Flanders from band 2 ;;; with Experimental System 123.90, Experimental Local-File 73.0, Experimental FILE-Server 22.0, Experimental Unix-Interface 11.0, Experimental Tape 18.0, Experimental KERMIT 34.0, Experimental ZMail 71.0, Experimental Lambda-Diag 15.0, microcode 1754, SDU Boot Tape 3.12, SDU ROM 8. ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:08:52 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defflavor tcp-stream-mixin ((socket nil) ;The tcp-socket (open nil) ;T if user has issued open (closing nil) ;T if remote side has closed (auto-push nil) ;T if open with auto-push (bytes-read 0) ;total bytes read on this socket (bytes-written 0) ;total bytes written on this socket (timeout nil) ;T if send timed out ) () (:method-combination (:daemon-with-or :base-flavor-last :listen)) (:gettable-instance-variables socket) (:inittable-instance-variables socket auto-push) ) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:08:56 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-stream-mixin :open) (&optional keyword &rest args) (setq args (copy-list args)) (let* ((host-list (member :remote-address args :test #'eq)) (host (second host-list)) (user-timeout (member :send-timeout args :test #'eq)) (current-timeout (* 30 60)) (open-socket (null args))) (when host-list (setf (second host-list) (parse-internet-address (second host-list)))) (setq args (append args `(:auto-push ,auto-push))) (if user-timeout (setq current-timeout (second user-timeout)) (setq args (append args `(:send-timeout ,current-timeout)))) (when (null socket) (setq socket (make-tcp-socket :keyword keyword))) (setq closing nil) (cond (open-socket ;Is socket already open? (setq open t) (send self :build-buffers) self) (t ;If user specified open keywords, open socket (loop (setq open (apply socket :open args)) (if (tcp:tcp-user-active socket) (ecase (send self :handle-replies) (:open ;All is well! (return self)) (:unreachable (cerror "Try again." "Remote Host ~S is unreachable" host)) (:reset (cerror "Try again." "Connection refused by ~S" host)) (:timeout (setq open nil) (send socket :abort) (incf current-timeout current-timeout) (cerror (format nil "Try again with timeout of ~D ticks." current-timeout) "Connection timed out") (let ((user-timeout (member :send-timeout args :test #'eq))) (setf (second user-timeout) current-timeout)))) (return self))))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:01 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-stream-mixin :handle-replies) (&optional no-hang-p) (loop (cond ((send socket :listen) ;Activity on the socket (let ((item (send socket :read-data))) (case (first item) (:open (send self :build-buffers) (return :open)) (:write-reply (incf bytes-written (fill-pointer (second item))) (send self :write-reply (second item)) (return :write-reply)) (:data (incf bytes-read (fill-pointer (second item))) (send self :read-reply (second item)) (when (eq (third item) :eof) (setq closing t)) (return :read-reply)) (:closing ;Remote side has closed (setq closing t) (return :remote-close)) (:reset (setq closing t) (setq open nil) (dolist (b (third item)) (send self :write-reply b)) ;;(cerror "Continue, treating as end-of-file" "Connection reset remotely") (return :reset)) (:close ;Socket closed out from under us (setq closing t) (setq open nil) ;;(cerror "Continue, treating as end-of-file" "Connection reset locally") (return :local-close)) ((:network-unreachable :host-unreachable :protocol-unreachable :port-unreachable) (setq closing t) (setq open nil) (send socket :abort) (return :unreachable)) (:timeout (setq timeout t) (return :timeout)) (otherwise ;;Ignore it )))) (no-hang-p ;No activity and no-hang (return nil)) (t ;No activity -- wait (wait-for-reply socket))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:09 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-stream-mixin :send-timeout) (&aux ok) (unwind-protect (progn (cerror "Reset timeout and continue" "Send timed out") (funcall socket :reset-timeout) (setq timeout nil) (setq ok t)) (unless ok (funcall socket :abort) (setq open nil)))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:14 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-stream-mixin :handle-all-replies) () (do ((count 0 (1+ count)) (event (send self :handle-replies t) (send self :handle-replies t))) ((null event) (plusp count)))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#44 at 3-Nov-87 15:31:49 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-stream-mixin :or :listen) () (or timeout closing)) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:17 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-buffered-stream :next-input-buffer) (&optional no-hang-p) (declare (values buffer start end)) (loop (cond ((not (fifo-empty-p input-buffer-fifo)) (let ((buffer (pop-fifo input-buffer-fifo))) (return (values buffer 0 (fill-pointer buffer))))) ((send self :handle-all-replies)) ((not open) (return nil)) (closing (return nil)) (no-hang-p (return nil)) (timeout (send self :send-timeout)) (t (wait-for-reply socket))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:21 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-buffered-stream :new-output-buffer) () (declare (values buffer start end)) (loop (cond (output-buffer-list (return (values (pop output-buffer-list) 0 output-buffer-size))) ((send self :handle-all-replies)) (timeout (send self :send-timeout)) (t (wait-for-reply socket))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:26 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-unbuffered-stream :tyi) (&optional eof) (loop (cond (untyi-char (return (prog1 untyi-char (setq untyi-char nil)))) (tyi-buffer (let* ((buffer tyi-buffer) (byte (aref buffer 0))) (setq tyi-buffer nil) (send socket :receive buffer) (return byte))) ((or closing (not open)) (if eof (global:signal 'sys:end-of-file :format-string "End of File on TCP stream") (return nil))) ((send self :handle-all-replies)) (timeout (send self :send-timeout)) (t (wait-for-reply socket))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:28 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-unbuffered-stream :listen) () (loop (cond (untyi-char (return t)) (tyi-buffer (return t)) ((or closing (not open)) (return t)) ((send self :handle-all-replies)) (timeout (return t)) (t (return nil))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:32 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-unbuffered-stream :tyi-no-hang) (&optional eof) (loop (cond (untyi-char (return (prog1 untyi-char (setq untyi-char nil)))) (tyi-buffer (let* ((buffer tyi-buffer) (byte (aref buffer 0))) (setq tyi-buffer nil) (send socket :receive buffer) (return byte))) ((or closing (not open)) (if eof (global:signal 'sys:end-of-file :format-string "End of File on TCP stream") (return nil))) ((send self :handle-all-replies)) (timeout (send self :send-timeout)) (t (return nil))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#43 at 3-Nov-87 15:09:36 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP-STREAM  " (defmethod (tcp-unbuffered-stream :tyo) (byte) (loop (cond ((not open) (return nil)) (tyo-buffer (let ((buffer tyo-buffer)) (setq tyo-buffer nil) (setf (aref buffer 0) byte) (setf (fill-pointer buffer) 1) (send socket :write-data buffer) (return t))) ((send self :handle-all-replies)) (timeout (send self :send-timeout)) (t (wait-for-reply socket))))) ))