;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*-
;;; Patch file for System version 123.169
;;; Reason:
;;;  Three problems found when trying TCP band transfer:
;;;    - If a TCP Server is closed from peek, the socket in the stream is set to NIL.
;;;      You then get an error in the scheduler when purge-servers tries to check if
;;;      the stream is open.
;;;    - TCP was improperly resetting hole offsets when the push-offset came exactly
;;;      at the end of a buffer and more buffers were queued.
;;;    - The TCP Disk Unit should close the stream with :abort t when asked to
;;;      :dispose of the unit -- All data transfer is synchronized such that
;;;      nothing is lost in the normal case -- and if you abort the transfer,
;;;      the Server isn't obligated to send the reset of the band to be
;;;      discarded by the user as it is with a normal graceful close.    
;;; Written 22-Dec-87 16:17:33 by pld at site Gigamos Cambridge
;;; while running on Jack Flanders from band 2
;;; with Experimental System 123.168, Experimental Local-File 73.3, Experimental FILE-Server 22.1, Experimental Unix-Interface 11.0, Experimental Tape 18.0, Experimental KERMIT 34.3, 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#51 at 22-Dec-87 16:18:06
#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 :close) (&optional mode)
  (when open
    (send self :force-output)
    (setq open nil)
    (apply socket :close (ncons mode))))

))

; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP.LISP#284 at 22-Dec-87 17:36:46
#10R TCP#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP  "

(defun process-data (socket packet)
  "Copies data into appropriate spots of receive buffers"
  (let* ((packet-offset (tcp-first-data-byte packet))	;offset in packet of first new data byte
	 (packet-seq (32-bit-plus (SEG.SEQ packet) (tcp-syn-bit packet)))	;seq num of 1st new data byte
	 (packet-bytes (- (length packet) packet-offset))	;number of new data bytes in packet
	 (packet-edge (32-bit-plus packet-seq packet-bytes))	;1+ last seq in packet
	 (push-offset (if (or (tcp-psh-bit-p packet) (tcp-fin-bit-p packet)) packet-bytes))
	 (old-RCV.NXT (RCV.NXT socket))		;Remember current version of RCV.NXT
	 new-buffer-seq)
    
    (when (32-bit-> (RCV.NXT socket) packet-seq)
      (let ((dup (32-bit-minus (RCV.NXT socket) packet-seq)))	;bytes of duplicate data
	(incf packet-offset dup)
	(setq packet-seq (32-bit-plus packet-seq dup))
	(decf packet-bytes dup)
	(cond ((null push-offset))
	      ((>= dup push-offset)
	       (setq push-offset nil))
	      (t
	       (decf push-offset dup)))))
    
    (when (32-bit-> packet-edge (RCV.LAST socket))
      (setf (RCV.LAST socket) packet-edge))
    
    ;;If the FIN bit is set, remember its sequence number.
    (when (tcp-fin-bit-p packet)
      (setf (tcp-user-remote-fin-sequence-number socket) packet-edge)
      (setf (RCV.LAST socket) (32-bit-plus packet-edge 1)))


    (when (plusp packet-bytes)
      ;;Copy as much data as possible to user receive buffers
      (multiple-value-setq (packet-bytes packet-offset packet-seq push-offset new-buffer-seq)
	(copy-packet-data-to-receive-data socket
					  (32-bit-minus (RCV.NXT socket) (tcp-user-receive-data-offset socket))
					  packet
					  packet-bytes
					  packet-offset
					  packet-seq
					  push-offset
					  :data))
      
      ;;Reply to filled receive buffers
      (reply-to-completed-receives socket)
      
      (when (plusp packet-bytes)
	(if (and (tcp-user-closed-p socket)
		 (tcp-user-discard-p socket)
		 (fifo-empty-p (tcp-user-receive-data socket)))
	    ;;User has closed, said we should discard excess data, and no buffers remain
	    (setf (RCV.NXT socket) packet-edge)
	  ;;Save as much as possible in existing saved-packet list
	  (progn
	    (multiple-value-bind (new-packet-bytes new-packet-offset)
		(copy-packet-data-to-saved-data socket
						new-buffer-seq
						packet
						packet-bytes
						packet-offset
						packet-seq
						push-offset)
	      (when (plusp new-packet-bytes)
		;;Some data still remains uncopied.  Drop it.
		(tcp-log :drop socket new-packet-bytes new-packet-offset)
		(tcp-stat-incf socket dropped-bytes new-packet-bytes)))))))

    ;;If all data up to FIN has been processed, signal user
    (check-if-fin-processed socket)
  
    ;;Finally, send an ACK if any in-sequence data has arrived
    (unless (= old-RCV.NXT (RCV.NXT socket))
      (when (assoc 'ack-delay-timeout (tcp-user-timeout-alist socket) :test #'eq)
	(tcp-stat-incf socket packets-while-ack-delayed))
      (setf (tcp-user-ack-needed-p socket) t))))

))

; From modified file DJ: L.NETWORK.IP-TCP.KERNEL; TCP.LISP#284 at 22-Dec-87 17:49:28
#10R TCP#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP  "

(defun copy-packet-data-to-receive-data (socket buffer-seq packet packet-bytes packet-offset packet-seq
					 push-offset keyword)
  "Copy data from a received packet into user receive buffers.  Return amount of uncopied data"
  (declare (values bytes-not-copied new-offset new-sequence new-push-offset new-buffer-seq))
  (do ((list (fifo-as-list (tcp-user-receive-data socket)) (cdr list))
       (packet-edge (32-bit-plus packet-seq packet-bytes)))	;sequence number of end of packet
      ((null list))				;Quit when we've run out of buffers
    (let* ((elt (car list))
	   (length (array-length (rcv-buffer elt)))
	   (buffer-edge (32-bit-plus buffer-seq length))
	   (buffer-offset 0)
	   (copy-bytes 0))
      ;;Sequence numbers of buffer: [buffer-seq,buffer-edge)
      (cond ((32-bit-< buffer-seq packet-seq)
	     ;;Packet starts after left edge of buffer
	     (unless (32-bit-<= buffer-edge packet-seq)
	       ;;Packet's left edge is in this buffer
	       (setq buffer-offset (32-bit-minus packet-seq buffer-seq))
	       (setq copy-bytes (min (- length buffer-offset) packet-bytes))))
	    ((32-bit->= packet-edge buffer-seq)
	     ;;Packet's right edge is in this buffer
	     (setq buffer-offset 0)
	     (setq copy-bytes (min length packet-bytes))))
      (when (plusp copy-bytes)
	(copy-tcp-data packet packet-offset elt buffer-offset copy-bytes socket keyword)
	(incf packet-offset copy-bytes)
	(setq packet-seq (32-bit-plus packet-seq copy-bytes))
	(decf packet-bytes copy-bytes)
	(when push-offset
	  (decf push-offset copy-bytes))
	(cond ((plusp packet-bytes)		;Entire packet doesn't fit in this buffer
	       (when push-offset
		 (setf (rcv-push-offset elt) (array-length (rcv-buffer elt)))))
	      ((zerop packet-bytes)
	       (unless (32-bit-<= buffer-edge packet-seq)
		 (adjust-push-offset elt (and push-offset (+ buffer-offset push-offset copy-bytes)))
		 (reset-holes socket)
		 (return)))
	      (t
	       (error "packet-bytes < 0"))))
      (setq buffer-seq buffer-edge)))
  (values packet-bytes packet-offset packet-seq push-offset buffer-seq))

))

; From modified file DJ: L.NETWORK.IP-TCP.SERVER; DISK.LISP#20 at 22-Dec-87 17:59:32
#10R TCP-APPLICATION#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP-APPLICATION")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; SERVER; DISK  "

(defmethod (serial-stream-disk-unit :dispose) ()
  (close stream :abort t))

))
