/*++

Copyright (c) 1997  Microsoft Corporation

Module Name:

    ARPSTRUC.H

Abstract:

	Structure definitions for the ARP protocol implementation

Author:

	Aaron Ogus (aarono)

Environment:

	Win32/COM

Revision History:

	Date    Author  Description
   =======  ======  ============================================================
   1/27/97  aarono  Original
   2/18/98  aarono  Added more fields to SEND for SendEx support
   6/6/98   aarono  Turn on throttling and windowing

--*/

#ifndef _ARPSTRUC_H_
#define _ARPSTRUC_H_

#include <windows.h>
#include <mmsystem.h>
#include <dplay.h>
#include "arpd.h"
#include "bufpool.h"
#include "bilink.h"
#include "mydebug.h"
//#include "threads.h"

#define VOL volatile
//
// Information about sent packets, tracked for operational statistics.
//

#define SENDSTAT_SIGN SIGNATURE('S','T','A','T')

typedef struct PROTOCOL *PPROTOCOL;

typedef struct _SENDSTAT {
#ifdef SIGN
	UINT				Signature;		// Signature for SIGN
#endif
	union {
		BILINK	StatList;		// linked on Send and later SESSION.
		struct _SENDSTAT *pNext;
	};	
	UINT    messageid;   
	UINT    sequence;		// sequence number
	UINT    serial;			// serial number
	UINT    tSent;			// tick time when this packet instance sent.
	UINT    LocalBytesSent;     // number of bytes sent on session at send time.
	UINT    RemoteBytesReceived;// last remote byte report at send time.
	UINT    tRemoteBytesReceived; // remote timestamp when received.
	UINT    bResetBias;
} SENDSTAT, *PSENDSTAT;

#define SEND_SIGN SIGNATURE('S','E','N','D')

typedef enum _TRANSMITSTATE {
	Start=0,			// Never sent a packet.
	Sending=1,			// Thread to send is running and xmitting.
	Throttled=2,		// Waiting for send bandwidth.
	WaitingForAck=3,	// Timer running, listening for ACKs.
	WaitingForId=4,   	// Waiting for a Send Id.
	ReadyToSend=5,		// Have stuff to xmit, waiting for thread.
	TimedOut=6,       	// Retry timed out.
	Cancelled=7,        // User cancelled send.
	UserTimeOut=8,		// Didn't try to send until too late.
	Done=9				// Finished sending, singalled sender.
	
} TRANSMITSTATE;

struct _SESSION;

// this Send is an ACK or NACK (OR'ed into SEND.dwFlags)
#define 	ASEND_PROTOCOL 	0x80000000

#pragma pack(push,1)

typedef struct _SEND{

#ifdef SIGN
	UINT		     Signature;		    // Signature for SIGN
#endif
	CRITICAL_SECTION SendLock;          // Lock for Send Structure
VOL	UINT             RefCount;          // @#$%!
	
VOL	TRANSMITSTATE    SendState;			// State of this message's transmission.

	// Lists and Links...
	
	union {
		struct _SEND *pNext;			// linking on free pool
		BILINK		   SendQ;			// linking on session send queue
	};
	BILINK         m_GSendQ;			// Global Priority Queue
	BILINK         TimeoutList;			// List of sends waiting for timeout (workaround MMTIMER cancel bug).
	struct _SESSION *pSession;          // pointer to SESSIONion(gets a ref)

	PPROTOCOL      pProtocol;           // pointer to Protocol instance that created us.

	// Send Information
	
	DPID           idFrom;
	DPID           idTo;
	WORD           wIdTo;				// index in table
	WORD           wIdFrom;             // index in table
	UINT		   dwFlags;             // Send Flags (include reliable)
	PBUFFER		   pMessage;			// Buffer chain describing message.
	UINT           MessageSize;			// Total size of the message.
	UINT           FrameDataLen;        // Data area of each frame.
	UINT           nFrames;			    // Number of frames for this message.

	UINT           Priority;            // Send Priority.

	// User cancel and complete info
	DWORD          dwMsgID;             // message id given to user, for use in cancel.
	LPVOID         lpvUserMsgID;		// user's own identifier for this send.
	BOOL           bSendEx;             // called through SendEx.

	// Vars for reliability
	BOOL           fSendSmall;
VOL BOOL       	   fUpdate;             // update to NS,NR NACKMask made by receive.
	UINT		   messageid;			// Message ID number.
	UINT           serial;              // serial number.
VOL	UINT		   OpenWindow;          // Number of sends we are trying to get outstanding
VOL	UINT           NS;		        	// Sequence Sent.
VOL	UINT           NR;					// Sequence ACKED.
	UINT           SendSEQMSK; 			// Mask to use. - BUGBUG: determine speed at start
VOL	UINT           NACKMask;            // Bit pattern of NACKed frames.
	

	// These are the values at NR - updated by ACKs
VOL	UINT		   SendOffset;			// Current offset we are sending.
VOL	PBUFFER        pCurrentBuffer;  	// Current buffer being sent.
VOL	UINT           CurrentBufferOffset; // Offset in the current buffer of next packet.

	// info to update link characteristics when ACKs come in.
	
	BILINK         StatList;			// Info for packets already sent.
	DWORD          BytesThisSend;		// number of bytes being sent in the current packet.

	// Operational Characteristics

VOL	UINT_PTR       uRetryTimer;         
    UINT           TimerUnique;

	UINT           RetryCount;          // Number of times we retransmitted.
	UINT           WindowSize;          // Maximum Window Size.
	UINT           SAKInterval;         // interval (frames) at which a SAK is required.
	UINT           SAKCountDown;		// countdown to 0 from interval.
	UINT           tLastACK;            // Time we last got an ACK.

	UINT           dwSendTime;			// time we were called in send.
	UINT           dwTimeOut;			// timeout time.

	//BUGBUG:
	UINT           PacketSize;          // Size of packets to send.
	UINT           FrameSize;           // Size of Frames for this send.

	// Completion Vars
	HANDLE         hEvent;              // Event to wait on for internal send.
	UINT           Status;              // Send Completion Status.

	PASYNCSENDINFO pAsyncInfo;          // ptr to Info for completing Async send(NULL=>internal send)
	ASYNCSENDINFO  AsyncInfo;           // actual info (copied at send call).

	DWORD		   tScheduled;			// the time we scheduled the retry;
	DWORD          tRetryScheduled;     // expected retry timer run time.
VOL	BOOL           bCleaningUp;			// we are on the queue but don't take a ref pls.
} SEND, *PSEND;

#pragma pack(pop)

#define RECEIVE_SIGN SIGNATURE('R','C','V','_')


// Receive buffers are in reverse receive order.  When they have all
// been received, they are then put in proper order.
typedef struct _RECEIVE {
#ifdef SIGN
	UINT		    Signature;		// Signature for SIGN
#endif
	union {
		BILINK          pReceiveQ;
		struct _RECEIVE *      pNext;
	};	
	BILINK		    RcvBuffList;     // List of receive buffers that make up the message.

	CRITICAL_SECTION ReceiveLock;

	struct _SESSION *pSession;

VOL	BOOL            fBusy;		// Someone is moving this receive.
	BOOL            fReliable;		// Whether this is a reliable receive.
VOL	BOOL            fEOM;           // Whether we received the EOM bit.

	UINT            command;      
	
	UINT			messageid;
VOL	UINT			MessageSize;

VOL	UINT            iNR;			// Absolute index of first receiving packet (reliable only).
VOL	UINT            NR;				// Last in sequence packet received.
VOL	UINT            NS;				// Highest packet number received.
VOL	UINT            RCVMask;		// bitmask of received packets (NR relative)

	PUCHAR          pSPHeader;
	UCHAR           SPHeader[0];

} RECEIVE, *PRECEIVE;

#pragma pack(push,1)

typedef struct _CMDINFO {
	WORD        wIdTo;		// index
	WORD        wIdFrom;	// index
	DPID        idTo;		// actual DPID
	DPID        idFrom;		// actual DPID
	
	UINT        bytes;      // read from ACK.
	DWORD       tRemoteACK; // remote time remote ACKed/NACKed
	
	UINT        tReceived;  // timeGetTime() when received.
	UINT        command;
	UINT        IDMSK;
	USHORT      SEQMSK;
	USHORT      messageid;
	USHORT      sequence;
	UCHAR       serial;
	UCHAR		flags;
	PVOID       pSPHeader;  // used to issue a reply.
} CMDINFO, *PCMDINFO;

#pragma pack(pop)

//BUGBUG: when a SESSIONion hasn't been used in a long time and contains no pending sends/receives,
//        age it out.

#define SESSION_SIGN SIGNATURE('S','E','S','S')

// since we now have a full byte for messagid and sequenne in the small headers, 
// we no longer have an advantage for full headers until we apply the new
// bitmask package, then we must transit to large frame for windows > 127 messages.

#define MAX_SMALL_CSENDS 	 29UL			// Maximum Concurrent Sends when using small frame headers
#define MAX_LARGE_CSENDS	 29UL			// Maxinum Concurrent Sends when using large frame headers (could make larger except for mask bits)
#define MAX_SMALL_DG_CSENDS  16UL			// Maximum concurrent datagrams when using small frame     
#define MAX_LARGE_DG_CSENDS  16UL           // Maximum Concurrent datagrams when using large frames.
#define MAX_SMALL_WINDOW     24UL
#define MAX_LARGE_WINDOW     24UL

typedef enum _SESSION_STATE {
	Open,				// When created and Inited.
	Closing,			// Don't accept new receives/sends.
	Closed				// gone.
} SESSION_STATE;

#define SERVERPLAYER_INDEX 0xFFFE

#define SESSION_THROTTLED			0x00000001		// session throttle is on.
#define SESSION_UNTHROTTLED         0x00000002		// unthrottle is deffered to avoid confusing GetMessageQueue.

/////////////////////////////////////////////////////////////////
//
//	Transition Matrix for Throttle Adjust
// 
//  Initial State	Event:
//					No Drops	1 Drop		>1 Drop
//
//  Start			+ Start		- Meta      -- Start
//								
//  Meta			+ Meta      - Stable    -- Meta
//
//  Stable          + Stable    - Stable    -- Meta
//
//
//  Engagement of Backlog Throttle goes to MetaStable State.
///////////////////////////////////////////////////////////////////

#define METASTABLE_GROWTH_RATE      4
#define METASTABLE_ADJUST_SMALL_ERR	12
#define METASTABLE_ADJUST_LARGE_ERR 25

#define START_GROWTH_RATE      50
#define START_ADJUST_SMALL_ERR 25
#define START_ADJUST_LARGE_ERR 50

#define STABLE_GROWTH_RATE      2
#define STABLE_ADJUST_SMALL_ERR 12
#define STABLE_ADJUST_LARGE_ERR 25

typedef enum _ThrottleAdjustState
{
	Begin=0,		// At start, double until drop or backlog
	MetaStable=1,	// Meta stable, large deltas for drops
	Stable=2		// Stable, small deltas for drops
} eThrottleAdjust;

typedef struct _SESSION {
	PPROTOCOL        pProtocol;			    // back ptr to object.

#ifdef SIGN
	UINT		  	 Signature;			    // Signature for SIGN
#endif

	// Identification

	CRITICAL_SECTION SessionLock;           // Lock for the SESSIONion.
VOL	UINT             RefCount;			    // RefCount for the SESSION.
VOL	SESSION_STATE    eState;
	HANDLE           hClosingEvent;         // Delete waits on this during close.
	
	DPID			 dpid;					// The remote direct play id for this session.
	UINT             iSession;              // index in the session table
	UINT             iSysPlayer;            // index in session table of sys player.
											// BUGBUG: if iSysPlayer != iSession, then rest of struct not req'd.

	BILINK			 SendQ;					// Priority order sendQ;
	BOOL             fFastLink;				// set True when link > 50K/sec, set False when less than 10K/sec.
	BOOL             fSendSmall;            // Whether we are sending small reliable frames.
	BOOL             fSendSmallDG;          // Whether we are sending small datagram frames.

	BOOL             fReceiveSmall;
	BOOL             fReceiveSmallDG;
											
	UINT			 MaxPacketSize;			// Largest packet allowed on the media.

	// Operating parameters -- Send

	// Common
	
	UINT             MaxCSends;				// maximum number of concurrent sends
	UINT             MaxCDGSends;           // maximum number of concurrent datagram sends

	// Reliable

	UINT			 FirstMsg;				// First message number being transmitted
	UINT			 LastMsg;				// Last message number being transmitted
	UINT             OutMsgMask;            // relative to FirstMsg, unacked messages

	UINT             nWaitingForMessageid;  // number of sends on queue that can't start sending because they don't have an id.

	// DataGram


	UINT             DGFirstMsg;             // First message number being transmitted
	UINT             DGLastMsg;              // Last message number being transmitted
	UINT             DGOutMsgMask;           // relative to FirstMsg, not-fully sent messages.

	UINT             nWaitingForDGMessageid; // number of sends on queue that can't start sending because they don't have an id.

	// Send stats are tracked seperately since sends may
	// no longer be around when completions come in.
	
	//BILINK           OldStatList;		
	

	// Operating parameters -- Receive

	// DataGram Receive.
	BILINK           pDGReceiveQ;            // queue of ongoing datagram receives

	// Reliable Receive.
	BILINK	         pRlyReceiveQ;			 // queue of ongoing reliable receives
	BILINK           pRlyWaitingQ;           // Queue of out of order reliable receives waiting.
											 // only used when PROTOCOL_NO_ORDER not set.
	UINT             FirstRlyReceive;
	UINT             LastRlyReceive;
	UINT             InMsgMask;              // mask of fully received receives, relative to FirstRlyReceive
 

	// Operational characteristics - MUST BE DWORD ALIGNED!!! - this is because we read and write them
	//                               without a lock and assume the reads and writes are atomic (not in combination)

	UINT             WindowSize;            // Max outstanding packets on a send - reliable
	UINT             DGWindowSize;          // Max outstanding packets on a send - datagram
	
	UINT             MaxRetry;				// Usual max retries before dropping.
	UINT             MinDropTime;			// Min time to retry before dropping.
	UINT             MaxDropTime;			// After this time always drop.

	UINT             LocalBytesReceived;    // Total Data Bytes received (including retries).
VOL	UINT             RemoteBytesReceived;   // Last value from remote.
VOL	DWORD            tRemoteBytesReceived;  // Remote time last value received.

	UINT			 LongestLatency;		// longest observed latency (msec)
	UINT             ShortestLatency;		// shortest observed latency(msec)
	UINT             LastLatency;           // last observed latency (msec)
	
	UINT             FpAverageLatency;		// average latency          (msec 24.8) (128 samples)
	UINT             FpLocalAverageLatency;	// Local average latency    (msec 24.8) (16 samples)

	UINT             FpAvgDeviation;        // average deviation of latency. (msec 24.8) (128 samples)
	UINT             FpLocalAvgDeviation;   // average deviation of latency. (msec 24.8) (16 samples)

	UINT             Bandwidth;				// latest observed bandwidth (bps)
	UINT			 HighestBandwidth;      // highest observed bandwidth (bps)

	// we will use changes in the remote ACK delta to isolate latency in the send direction.
	UINT             RemAvgACKDelta;		// average clock delta between our send time (local time) and remote ACK time (remote time).
	UINT             RemAvgACKDeltaResidue;
	UINT             RemAvgACKBias;			// This value is used to pull the clock delta into a safe range (not near 0 or -1)
											// that won't risk hitting the wraparound when doing calculations

	// Throttle statistics
	DWORD			 dwFlags;               // Session Flags - currently just "throttle on/off"(MUST STAY THIS WAY)
	UINT			 SendRateThrottle;	    // current rate (bps) at which we are throttling.
	DWORD            bhitThrottle;          // we hit a throttle
	DWORD            tNextSend;				// when we are allowed to send again.
	DWORD            tNextSendResidue;		// residual from calculating next send time
	DWORD_PTR		 uUnThrottle;
	DWORD            UnThrottleUnique;
	DWORD            FpAvgUnThrottleTime;   // (24.8) how late Unthrottle usually called. (throttle when send is this far ahead)
											// last 16 samples, start at 5 ms.

	DWORD            tLastSAK;				// last time we asked for an ACK

	CRITICAL_SECTION SessionStatLock;        // [locks this section ------------------------------------------- ]
	BILINK           DGStatList;             // [Send Statistics for Datagrams (for reliable they are on Sends) ]
	DWORD            BytesSent;				 // [Total Bytes Sent to this target                                ]
	DWORD			 BytesLost;				 // [Total Bytes Lost on the link.							 		]
	DWORD            bResetBias;             // [Counts down to reset latency bias								]
											 // [---------------------------------------------------------------]

	eThrottleAdjust  ThrottleState;			// ZEROINIT puts in Start
	DWORD            GrowCount;				// number of times we grew in this state
	DWORD            ShrinkCount;			// number of times we shrank in this state
	DWORD            tLastThrottleAdjust;   // remember when we last throttled to avoid overthrottling.
} SESSION, *PSESSION;

#endif
