;;; -*- Mode:Lisp; Readtable:CL; Package:USER; Base:10; Patch-File:T -*-
;;; Patch file for System version 123.30
;;; Reason:
;;;  (tcp-socket :close) takes an optional "mode" argument which defaults to :discard.
;;;  If explicitly called with NIL, it should also default to :discard -- the callers
;;;  who call it that way are simply trying to use mode :abort.  Thus: NIL or :discard
;;;  means discard further received data, T or :abort means abort the connection, and
;;;  :normal means close the connection but allow :receive operations to get further data
;;; Written 6-Oct-87 17:33:38 by pld at site LMI Cambridge
;;; while running on Jack Flanders from band 2
;;; with Experimental System 123.28, 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.LISP#274 at 6-Oct-87 17:33:41
#10R TCP#: 
(COMPILER-LET ((*PACKAGE* (GLOBAL:PKG-FIND-PACKAGE "TCP")))
  (COMPILER::PATCH-SOURCE-FILE "SYS: NETWORK; IP-TCP; KERNEL; TCP  "


(defop (tcp-socket :close) (&optional (mode :discard))
  ;;mode = nil or :discard -- throw away incoming data until FIN
  ;;mode = :normal -- allow further :receive's
  ;;mode = :abort or t -- abort connection
  (ecase mode
    ((:discard nil) (setq mode :discard))
    ((:abort t) (setq mode :abort))
    (:normal))
  (cond ((null (tcp-user-state self)))
	((eq (tcp-user-state self) :closed))
	((eq mode :abort)
	 (send self :abort))
	(t
	 ;;Normal graceful close
	 (with-lock ((tcp-user-lock self))
	   (tcp-log :close self)
	   (cond ((setf (tcp-user-discard-p self) (eq mode :discard))
		  ;;Max out the window.  Some (broken) implementations treat the window as a SIGNED number...
		  (setf (RCV.WND self) (floor 65535 2))
		  (let ((saved-data (saved-but-unacknowledged-data self)))
		    (when (plusp saved-data)
		      ;;We have data saved but not given to user.  Acknowledge it all.
		      (setf (RCV.NXT self) (32-bit-plus (RCV.NXT self) saved-data))))
		  (do ((elt (pop-fifo (tcp-user-saved-packets self))
			    (pop-fifo (tcp-user-saved-packets self))))
		      ((null elt))
		    (free-tcp-buffer (rcv-buffer elt)))
		  (let ((receives (fifo-as-list (tcp-user-receive-data self))))
		    (setf (tcp-user-receive-data self) nil)
		    (setf (tcp-user-receive-data-length self) 0)
		    (setf (tcp-user-receive-data-offset self) 0)
		    (push-fifo `(:close ,(mapcar #'rcv-buffer receives)) (tcp-user-packet-list self))))
		 (t
		  (push-fifo '(:close) (tcp-user-packet-list self))))
	   (ecase (tcp-user-state self)
	     (:CLOSED
	      ;;(error "connection does not exist")
	      nil)
	     ((:LISTEN :SYN-SENT)
	      (tcp-stat-incf self (if (eq (tcp-user-state self) :listen)
				      in-connection-aborts
				    out-connection-aborts))
	      (flush-tcp-socket self)
	      t)
	     (:SYN-RECEIVED
	      (setf (tcp-user-closed-p self) t)
	      (setf (tcp-user-fin-needed-p self) t)
	      (when (fifo-empty-p (tcp-user-send-data self))
		(change-state self :FIN-WAIT-1)
		(send-tcp-packets self))
	      t)
	     (:ESTABLISHED
	      (setf (tcp-user-closed-p self) t)
	      (setf (tcp-user-fin-needed-p self) t)
	      (change-state self :FIN-WAIT-1)
	      (send-tcp-packets self)
	      t)
	     (:CLOSE-WAIT
	      (setf (tcp-user-closed-p self) t)
	      (setf (tcp-user-fin-needed-p self) t)
	      (change-state self :CLOSING)
	      (send-tcp-packets self)
	      t)
	     ((:FIN-WAIT-1 :FIN-WAIT-2 :CLOSING :LAST-ACK :TIME-WAIT)
	      ;;(error "connection closing")
	      nil))))))

))
