(FILECREATED "29-May-85 14:20:46" {ERIS}<LISP>INTERMEZZO>PATCHES>BSPPATCH.;1 6655   

      changes to:  (VARS BSPPATCHCOMS))


(* Copyright (c) 1985 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT BSPPATCHCOMS)

(RPAQQ BSPPATCHCOMS ((FNS \BSP.HANDLE.ACK)
		     (INITVARS (\BSP.MIN.ADATA.TIMEOUT 500)
			       (\BSP.MAX.ADATA.TIMEOUT 10000))
		     (GLOBALVARS \BSP.MIN.ADATA.TIMEOUT \BSP.MAX.ADATA.TIMEOUT)))
(DEFINEQ

(\BSP.HANDLE.ACK
  [LAMBDA (PUP SOCKET)                                       (* bvm: "29-May-85 14:12")

          (* * Handle an ACK pup. This is a little messy. The ACK's id tells how far partner has gotten in the stream.
	  Assuming this ack was in response to an ADATA of ours, we need to retransmit anything that we sent before that ADATA
	  which isn't acknowledged in this ack. Finally, the body of the ack gives us an update of partner's allocation)


    (PROG (THISID NEXTPUP OLDPUP ADATACOUNT ACKDATA OUTQUEUE INTERRUPTPUP)
          (COND
	    ((OR (NOT (\RTP.FILTER SOCKET PUP T))
		 (ILESSP (SETQ THISID (fetch PUPID of PUP))
			 (fetch LASTACKID of SOCKET)))       (* not for us, or is a duplicate/delayed ack)
	      (RELEASE.PUP PUP)
	      (RETURN)))
          [COND
	    ((fetch ACKREQUESTED of SOCKET)

          (* This is presumably in response to our last ADATA, so notice how long it took. Update our timeout = 2 * avg round 
	  trip delay, exponentially aged over the last 8 samples)


	      (replace ADATATIMEOUT of SOCKET
		 with (LRSH [IPLUS (ITIMES 7 (fetch ADATATIMEOUT of SOCKET))
				   (IMAX \BSP.MIN.ADATA.TIMEOUT
					 (IMIN \BSP.MAX.ADATA.TIMEOUT
					       (LLSH (CLOCKDIFFERENCE (fetch LASTADATATIME
									 of SOCKET))
						     1]
			    3]
          (replace LASTACKID of SOCKET with THISID)
          (SETQ OUTQUEUE (fetch BSPOUTPUTQ of SOCKET))       (* Now figure out who is acked and who needs 
							     retransmitting)
          [COND
	    ((fetch INTERRUPTOUT of SOCKET)
	      (SETQ INTERRUPTPUP (\SEARCH.OUTPUTQ SOCKET T]
          (UNINTERRUPTABLY
              (SETQ OLDPUP (fetch SYSQUEUEHEAD of OUTQUEUE))
                                                             (* Empty out the queue and refill it below)
	      (replace SYSQUEUEHEAD of OUTQUEUE with (replace SYSQUEUETAIL of OUTQUEUE with NIL)))
          (COND
	    (INTERRUPTPUP                                    (* Retransmit interrupts immediately)
			  (replace EPREQUEUE of INTERRUPTPUP with OUTQUEUE)
			  (SENDPUP (fetch PUPSOC of SOCKET)
				   INTERRUPTPUP)))
          (COND
	    ((fetch ACKREQUESTED of SOCKET)
	      (SETQ ADATACOUNT (fetch ADATACOUNT of SOCKET))
                                                             (* This lets us know whether a pup was sent before or 
							     after last adata)
	      (replace ACKREQUESTED of SOCKET with NIL)))
          (while OLDPUP
	     do (SETQ NEXTPUP (fetch QLINK of OLDPUP))
		(replace QLINK of OLDPUP with NIL)
		(COND
		  ((EQ (fetch PUPTYPE of OLDPUP)
		       \PT.INTERRUPT)                        (* We retransmitted it above, so we should not be 
							     seeing this!)
		    (\ENQUEUE OUTQUEUE OLDPUP))
		  ((IGEQ (IDIFFERENCE THISID (fetch PUPID of OLDPUP))
			 (IDIFFERENCE (fetch PUPLENGTH of OLDPUP)
				      \PUPOVLEN))            (* has been acked, release it)
		    (add (fetch #UNACKEDPUPS of SOCKET)
			 -1)
		    (add (fetch #UNACKEDBYTES of SOCKET)
			 (IDIFFERENCE \PUPOVLEN (fetch PUPLENGTH of OLDPUP)))
		    (add (fetch PUPALLOCCOUNT of SOCKET)
			 1)                                  (* one more pup successfully received)
		    (RELEASE.PUP OLDPUP))
		  ((AND ADATACOUNT (IGREATERP ADATACOUNT (fetch AUXWORD of OLDPUP)))
                                                             (* This pup was originally sent before our last ADATA, 
							     so retransmit it)
		    [\TRANSMIT.STRATEGY SOCKET OLDPUP (COND
					  ([AND (fetch QLINK of OLDPUP)
						(ILEQ ADATACOUNT (fetch AUXWORD
								    of (fetch QLINK of OLDPUP]
					    (SETQ ADATACOUNT NIL))
					  (T (QUOTE NO]      (* Maybe make it an ADATA if this is the last thing 
							     we're retransmitting, else make it just DATA)
		    (replace EPREQUEUE of OLDPUP with OUTQUEUE)
		    (SENDPUP (fetch PUPSOC of SOCKET)
			     OLDPUP))
		  (T (\ENQUEUE OUTQUEUE OLDPUP)))
		(SETQ OLDPUP NEXTPUP))

          (* * Now update allocations)


          [COND
	    ((IGREATERP (fetch PUPALLOCCOUNT of SOCKET)
			\BSP.ALLOCHYSTERESIS)                (* We've been doing okay for a while with no 
							     congestion, so increase our max pup allocation)
	      (replace PUPALLOCCOUNT of SOCKET with 0)
	      (COND
		((ILESSP (fetch MAXPUPALLOC of SOCKET)
			 \BSP.MAXPUPALLOC)
		  (add (fetch MAXPUPALLOC of SOCKET)
		       1]
          (SETQ ACKDATA (fetch PUPCONTENTS of PUP))
          (replace BYTESPERPUP of SOCKET with (IMIN (fetch ACKBYTESPERPUP of ACKDATA)
						    \MAX.PUPLENGTH))
          (replace PUPALLOC of SOCKET with (IMAX (IMIN (fetch MAXPUPALLOC of SOCKET)
						       (IDIFFERENCE (fetch ACKPUPS of ACKDATA)
								    (fetch #UNACKEDPUPS of SOCKET)))
						 0))         (* number of pups we can still send)
          (replace BYTEALLOC of SOCKET with (IMAX (IDIFFERENCE (fetch ACKBYTES of ACKDATA)
							       (fetch #UNACKEDBYTES of SOCKET))
						  0))
          (RELEASE.PUP PUP)
          (NOTIFY.EVENT (fetch BSPINPUTEVENT of SOCKET))     (* Actually, notifying that allocation may have 
							     changed)
          (\SETBSPTIMEOUT SOCKET)
          (SETUPTIMER \BSP.INACTIVITY.TIMEOUT (fetch INACTIVITYTIMER of SOCKET])
)

(RPAQ? \BSP.MIN.ADATA.TIMEOUT 500)

(RPAQ? \BSP.MAX.ADATA.TIMEOUT 10000)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \BSP.MIN.ADATA.TIMEOUT \BSP.MAX.ADATA.TIMEOUT)
)
(PUTPROPS BSPPATCH COPYRIGHT ("Xerox Corporation" 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (435 6398 (\BSP.HANDLE.ACK 445 . 6396)))))
STOP