;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*- ;;; Patch file for System version 123.131 ;;; Reason: ;;; Make TCP Urgent mode work for tcp-streams. ;;; - TCP wasn't setting urgent bit for a single byte of data ;;; - Netstat wasn't displaying SND.UP and RCV.UP usefully ;;; - tcp-stream now lets you :set-urgent-output to specify that outgoing data is Urgent. ;;; - tcp-stream now lets you :urgent-input to see if unread Urgent data exists. ;;; Written 30-Nov-87 17:03:06 by pld at site Gigamos Cambridge ;;; while running on Jack Flanders from band 2 ;;; with Experimental System 123.129, Experimental Local-File 73.3, Experimental FILE-Server 22.1, 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.LISP#283 at 30-Nov-87 17:03:19 #10R TCP#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP  " (defun build-tcp-packet (tp) "Builds and returns a TCP packet for TCP connection tp" (declare (values buffer-list byte-count)) (let* ((header (get-tcp-header)) (buffers (ncons header)) (data-to-send 0) (ISS (ISS tp)) (SND.UNA (SND.UNA tp)) (SND.NXT (SND.NXT tp)) (SND.UP (SND.UP tp))) (setf (tcp-source-port header) (tcp-user-local-port tp)) (setf (tcp-destination-port header) (tcp-user-remote-port tp)) (setf (tcp-sequence-number header) SND.NXT) (setf (tcp-ack-number header) (RCV.NXT tp)) (setf (tcp-reserved-1 header) 0) (setf (tcp-reserved-2 header) 0) (setf (tcp-flags header) 0) (cond ((= ISS SND.NXT) (setf (tcp-data-offset header) 6) (setf (fill-pointer header) 24) (setf (tcp-syn-bit header) 1) (setf (aref header 20) tcp-opt-mss) (setf (aref header 21) 4) (let ((mss (tcp-user-interface-mss tp))) (setf (aref header 22) (ldb (byte 8 8) mss)) (setf (aref header 23) (ldb (byte 8 0) mss)))) (t (setf (tcp-data-offset header) 5) (setf (fill-pointer header) 20))) (unless (member (tcp-user-state tp) '(:CLOSED :LISTEN :SYN-SENT)) (setf (tcp-ack-bit header) 1)) (setf (tcp-window header) (RCV.WND tp)) (cond ((and SND.UP (32-bit->= SND.UP SND.NXT)) (setf (tcp-urg-bit header) 1) (setf (tcp-urgent-pointer header) (32-bit-minus SND.UP SND.NXT))) (t (setf (tcp-urgent-pointer header) 0))) ;; Add user data to list of buffers (setq data-to-send (min (- (tcp-user-send-data-length tp) (tcp-user-send-data-offset tp)) ;user data (tcp-user-remote-mss tp) ;remote end's max segment (tcp-user-interface-mss tp))) ;max data in int-pkt (unless (eq (tcp-user-state tp) :SYN-SENT) (setq data-to-send (min (- (SND.WND tp) (32-bit-minus SND.NXT SND.UNA)) data-to-send))) (when (plusp data-to-send) (do ((left data-to-send) (current-offset 0) (start-offset (- (tcp-user-send-data-offset tp) ;sent but unACKed (if (= ISS SND.UNA) 1 0))) ;but don't count SYN (list (fifo-as-list (tcp-user-send-data tp)) (cdr list))) ((or (null list) (not (plusp left))) (unless (zerop left) (cerror "continue" "Not enough data in send list"))) (let ((length (length (first list)))) (cond ((> start-offset current-offset) ;;At least front of this buffer gets skipped... (let ((skip (- start-offset current-offset))) (unless (>= skip length) (push (make-array (min (- length skip) left) :element-type '(unsigned-byte 8) :displaced-to (first list) :displaced-index-offset skip) buffers) (decf left (length (first buffers)))))) ((> length left) ;;Tail of this buffer is skipped... (push (make-array left :element-type '(unsigned-byte 8) :displaced-to (first list)) buffers) (return)) (t ;;Entire buffer included (push (first list) buffers) (decf left length))) (incf current-offset length))) (setq buffers (nreverse buffers)) ;;If this buffer includes PUSHed data, set the PUSH bit (when (and (tcp-user-push-sequence-number tp) (32-bit-< (tcp-user-push-sequence-number tp) (32-bit-plus SND.NXT data-to-send))) (setf (tcp-psh-bit header) 1))) ;;Have we included the last data byte the user's given us? (when (= (+ data-to-send (tcp-user-send-data-offset tp)) (tcp-user-send-data-length tp)) (when (tcp-user-auto-push tp) ;; In auto-push mode, set the PUSH bit (setf (tcp-psh-bit header) 1)) ;; Set the FIN bit too if the user has closed the connection (when (tcp-user-fin-needed-p tp) (setf (tcp-fin-bit header) 1))) ;; Calculate and store the TCP checksum (store-tcp-checksum buffers (tcp-user-ip-header tp) (tcp-user-local-host-p tp)) ;; Return the list of buffers we built (values buffers (max data-to-send 0)))) )) ; From modified file DJ: L.NETWORK.KERNEL; NETSTAT.LISP#102 at 30-Nov-87 17:03:32 #10R NETWORK#: (COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "NETWORK"))) (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; KERNEL; NETSTAT  " (defun tcp-socket-normal-fields (socket) (list (tv:scroll-parse-item `(:function ,#'(lambda (n) (or (tcp:ISS n) 0)) (,socket) NIL (" ISS = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:SND.WND n) 0)) (,socket) NIL (" SND.WND = ~5D")) `(:function ,#'(lambda (n) (or (tcp:SND.NXT n) 0)) (,socket) NIL (" SND.NXT = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:SND.UP n) 0)) (,socket) NIL (" SND.UP = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:SND.WL2 n) 0)) (,socket) NIL (" SND.WL2 = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:SND.UNA n) 0)) (,socket) NIL (" SND.UNA = ~16,8,'0R"))) (tv:scroll-parse-item `(:function ,#'(lambda (n) (or (tcp:IRS n) 0)) (,socket) NIL (" IRS = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:RCV.WND n) 0)) (,socket) NIL (" RCV.WND = ~5D")) `(:function ,#'(lambda (n) (or (tcp:RCV.NXT n) 0)) (,socket) NIL (" RCV.NXT = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:RCV.UP n) 0)) (,socket) NIL (" RCV.UP = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:SND.WL1 n) 0)) (,socket) NIL (" SND.WL1 = ~16,8,'0R")) `(:function ,#'(lambda (n) (or (tcp:tcp-user-remote-fin-sequence-number n) 0)) (,socket) NIL (" FIN = ~16,8,'0R"))) (tv:scroll-parse-item `(:function tcp:tcp-user-remote-mss (,socket) NIL (" Remote MSS = ~D")) `(:function tcp:tcp-user-interface-mss (,socket) NIL (" Local MSS = ~D")) `(:function tcp:tcp-user-precedence (,socket) NIL (" Precedence = ~D")) `(:function tcp:tcp-user-security (,socket) NIL (" Security = ~D")) `(:function tcp:tcp-user-compartment (,socket) NIL (" Compartment = ~D")) `(:function tcp:tcp-user-handling (,socket) NIL (" Handling = ~D")) `(:function tcp:tcp-user-tcc (,socket) NIL (" TCC = ~D"))) (tv:scroll-parse-item `(:function tcp:tcp-user-open-timeout (,socket) NIL (" Timeouts: Open = ~D")) `(:function tcp:tcp-user-send-timeout (,socket) NIL (" Send = ~D")) `(:function tcp:tcp-user-cumulative-timeout (,socket) NIL (" Cumulative = ~D")) `(:function tcp:tcp-user-ack-delay (,socket) NIL (" ACK = ~D")) `(:function tcp:tcp-user-smoothed-round-trip-time (,socket) NIL (" SRTT = ~4F")) `(:function tcp:tcp-user-retransmission-timeout (,socket) NIL (" RTO = ~4F")) `(:function tcp:tcp-user-closed-p (,socket) NIL (" Closed = ~D"))) (tv:scroll-parse-item `(:function tcp:tcp-user-send-data-length (,socket) NIL (" Send Length = ~D")) `(:function tcp:tcp-user-send-data-offset (,socket) NIL (" Sent Unacknowledged = ~D")) `(:function ,#'(lambda (n) (- (tcp:tcp-user-send-data-length n) (tcp:tcp-user-send-data-offset n))) (,socket) NIL (" Unsent = ~D")) `(:function tcp:tcp-user-receive-data-length (,socket) NIL (" Receive Length = ~D")) `(:function ,#'(lambda (n) (- (tcp:tcp-user-receive-data-length n) (tcp:tcp-user-receive-data-offset n))) (,socket) NIL (" Receive Free = ~D"))) (sent-statistics (tcp:tcp-user-statistics-block socket) " ") (rcvd-statistics (tcp:tcp-user-statistics-block socket) " ") )) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:04:55 #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 (urgent-output nil) ;T if in Urgent mode for output (urgent-input nil) ;T if in Urgent mode for input (urgent-offset nil) ;offset of urgent data ) () (:method-combination (:daemon-with-or :base-flavor-last :listen)) (:gettable-instance-variables socket urgent-output urgent-input) (:settable-instance-variables urgent-output) (:inittable-instance-variables socket auto-push) ) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:04:57 #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 (let ((length (fill-pointer (second item))) (offset (fourth item))) (when offset ;Remember last known offset of urgent data (setq urgent-offset (+ bytes-read offset 1)) (setq urgent-input t)) (incf bytes-read length) (when (eq (third item) :eof) (setq closing t)) (send self :read-reply (second item) urgent-offset)) (return :read-reply)) (:urgent ;should signal this somehow... (setq urgent-input t)) (: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 (send self :wait-for-reply))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:05:02 #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 :read-reply) (buffer offset) (push-fifo (cons buffer offset) input-buffer-fifo)) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:05:05 #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 ((send self :handle-all-replies)) ((not (fifo-empty-p input-buffer-fifo)) (let* ((elt (pop-fifo input-buffer-fifo)) (buffer (car elt)) (offset (cdr elt))) ;;The following clears urgent-input mode if the urgent byte is in this buffer. (setq urgent-input (not (null offset))) (return (values buffer 0 (fill-pointer buffer))))) ((not open) (return nil)) (closing (return nil)) (no-hang-p (setq urgent-input (and urgent-offset (> urgent-offset bytes-read))) (return nil)) (timeout (send self :send-timeout)) (t (send self :wait-for-reply #'(lambda (b o c to) (or (not (fifo-empty-p (cdr b))) (not (cdr o)) (cdr c) (cdr to))) (locf input-buffer-fifo) (locf open) (locf closing) (locf timeout)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:05:27 #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 ((send self :handle-all-replies)) (output-buffer-list (return (values (pop output-buffer-list) 0 output-buffer-size))) (timeout (send self :send-timeout)) (t (send self :wait-for-reply #'(lambda (x y) (or (cdr x) (cdr y))) (locf output-buffer-list) (locf timeout)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:05:46 #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 :read-reply) (buffer offset) ;;All this says is whether the urgent offset is within THIS buffer... (setq urgent-input (and offset (>= offset (length buffer)))) (setq tyi-buffer buffer)) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:05:51 #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 ((send self :handle-all-replies)) (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) (setq urgent-input (and urgent-offset (>= urgent-offset bytes-read))) (return byte))) ((or closing (not open)) (if eof (global:signal 'sys:end-of-file :format-string "End of File on TCP stream") (return nil))) (timeout (send self :send-timeout)) (t (send self :wait-for-reply #'(lambda (u b o c to) (or (cdr u) (cdr b) (not (cdr o)) (cdr c) (cdr to))) (locf untyi-char) (locf tyi-buffer) (locf open) (locf closing) (locf timeout)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:05:58 #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 (unwind-protect (cond ((send self :handle-all-replies)) (untyi-char (return t)) (tyi-buffer (return t)) ((or closing (not open)) (return t)) (timeout (return t)) (t (return nil))) (setq urgent-input (and urgent-offset (>= urgent-offset bytes-read)))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:06:01 #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 ((send self :handle-all-replies)) (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) (setq urgent-input (and urgent-offset (>= urgent-offset bytes-read))) (return byte))) ((or closing (not open)) (if eof (global:signal 'sys:end-of-file :format-string "End of File on TCP stream") (return nil))) (timeout (send self :send-timeout)) (t (return nil))))) )) ; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP-STREAM.LISP#49 at 1-Dec-87 12:06:06 #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 ((send self :handle-all-replies)) ((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 :urgent urgent-output) (return t))) (timeout (send self :send-timeout)) (t (send self :wait-for-reply #'(lambda (b o to) (or (cdr b) (not (cdr o)) (cdr to))) (locf tyo-buffer) (locf open) (locf timeout)))))) ))