00001 using System; 00002 using System.Collections; 00003 using System.Threading; 00004 00005 namespace SmartDeviceGUIClient 00006 { 00011 public class NACKManager {} 00012 00013 // public class NACKManager2 00014 // { 00015 // /** Fields **/ 00016 // private NackQueue nackQueue; // queue of NACKs waiting to be sent out 00017 // private TransmissionQueue txQueue; // the transmission queue in which to output things 00018 // private RemoteHostComms thisRemoteHost; 00019 // 00020 // /** Constructors **/ 00021 // /// <summary> 00022 // /// Creates a new NACK Manager, outputting NACKs and retransmissions into a given TransmissionQueue 00023 // /// </summary> 00024 // public NACKManager2(RemoteHostComms thisRemoteHost) { 00025 // this.thisRemoteHost = thisRemoteHost; 00026 // nackQueue = new NackQueue(); 00027 // this.txQueue = thisRemoteHost.TxQueue; 00028 // } 00029 // 00030 // public void ResetConnections() { 00031 // Console.WriteLine("NACK Manager Reset Starting ..."); 00032 // nackQueue.Clear(); 00033 // Console.WriteLine("... NACK Manager Reset Complete"); 00034 // } 00035 // 00036 // /// <summary> 00037 // /// returns null if no nacks waiting otherwise returns the next nack to be issued. 00038 // /// </summary> 00039 // /// <returns>Next NACK to be issued, or null if there are none</returns> 00040 // public NackInfo GetNextNack() { 00041 // /* only one thread should be calling this at any given time, so no need to lock */ 00042 // if (nackQueue.IsEmpty) { return null; } 00043 // else return nackQueue.Dequeue(); 00044 // } 00045 // 00046 // public void ProcessReceivedSegmentHeaders(ref SegmentHeaders newHeaders) { 00047 // /* examines headers to see which segments need to be retransmitted */ 00048 // /* calculate end point of nack range 00049 // * use it in a for loop to add a nack retransmision message to the relevant queue */ 00050 // uint lastNACK; 00051 // uint firstNACK; 00052 // ushort destination; 00053 // //Console.WriteLine("NACK Manager: Process Received Segment Headers"); 00054 // if (newHeaders.IsNACK) { // Retransmit 00055 // firstNACK = newHeaders.NackInfo.SequenceNumber; 00056 // if (newHeaders.NackInfo.IsRanged) { lastNACK = firstNACK + newHeaders.NackInfo.Range; } 00057 // else { lastNACK = firstNACK; } 00058 // destination = newHeaders.SourceDeviceID; // this should always be the same. 00059 // 00060 // // TODO: Fix so that range can wrap round. 00061 // for (uint i = firstNACK; i <= lastNACK; i++) { 00062 // // grab segment from retransmission buffer 00063 // Segment tempSegment = thisRemoteHost.RetransmissionBuffer.GetSegment(i); 00064 // // encapsulate segment in retransmission message 00065 // RetransmissionMessage retransMessage = new RetransmissionMessage(tempSegment); 00066 // // set the destination of the retransmission 00067 // retransMessage.Destination = destination; 00068 // // plonk message into the correct transmission queue 00069 // TransmissionQueueEntry[] entries = TransmissionQueueEntry.FromMessage(retransMessage); 00070 // txQueue.Enqueue(entries, false); 00071 // Console.WriteLine("NACK Manager: Issued Reransmision of #" + i); 00072 // } 00073 // } 00074 // } 00075 // 00076 // /// <summary> 00077 // /// Initiates the issuing of a single-segment NACK 00078 // /// </summary> 00079 // /// <param name="segmentNumber">Sequence number of the missing segment</param> 00080 // public void IssueNACK(uint segmentNumber) { 00081 // SendNACK(new NackInfo(segmentNumber)); 00082 // } 00083 // 00084 // /// <summary> 00085 // /// Initiates the issuing of a contigious multi-segment NACK 00086 // /// </summary> 00087 // /// <param name="segmentNumber">Sequence number of the first missing segment in the sequence</param> 00088 // /// <param name="Range">The number of subsequent missing segments</param> 00089 // public void IssueNACK(uint segmentNumber, long range) { 00090 // for (long offset = 0; offset < range; offset++) { 00091 // IssueNACK((uint)(segmentNumber + offset)); 00092 // } 00093 // //SendNACK(new NackInfo(segmentNumber, (uint)range)); 00094 // } 00095 // 00096 // private void SendNACK(NackInfo nackInfo) { 00097 // lock (txQueue.SyncRoot) { 00098 // if (txQueue.IsEmpty) { 00099 // /* create no-op message */ 00100 // Message noopMsg = new EmptyMessage(); 00101 // noopMsg.Destination = thisRemoteHost.RemoteDeviceID; 00102 // /* segmentise */ 00103 // TransmissionQueueEntry[] buffer = TransmissionQueueEntry.FromMessage(noopMsg); 00104 // /* place results in segment queue */ 00105 // // make sure this all happens in a monitor, so we get them all together 00106 // txQueue.EnqueueUnprotected(buffer, false); 00107 // } 00108 // nackQueue.Enqueue(nackInfo); 00109 // Console.WriteLine("NACK Manager: NACK Sent for #" + nackInfo.SequenceNumber + " Range: " + (nackInfo.IsRanged ? nackInfo.Range.ToString() : "N/A")); 00110 // Monitor.PulseAll(txQueue.SyncRoot); 00111 // } 00112 // } 00113 // } 00114 00115 /*****************************************************************************/ 00116 public class NackInfo { 00118 bool isRanged; 00119 uint sequenceNumber; 00120 uint range; 00121 00123 public NackInfo(uint sequenceNumber) { 00124 this.isRanged = false; 00125 this.sequenceNumber = sequenceNumber; 00126 } 00127 00128 public NackInfo(uint sequenceNumber, uint range) { 00129 this.isRanged = true; 00130 this.sequenceNumber = sequenceNumber; 00131 this.range = range; 00132 } 00133 00135 public bool IsRanged { get { return isRanged; }} 00136 public uint SequenceNumber { get { return sequenceNumber; } } 00137 public uint Range { get { return range; } } 00138 00139 00140 } 00141 00142 00143 /*****************************************************************************/ 00147 // class NackQueue : Queue { 00148 // public NackQueue() : base() {} 00149 // 00150 // /// <summary> 00151 // /// Adds an item to the Nack Queue. 00152 // /// Thread Safe 00153 // /// </summary> 00154 // /// <param name="nackInfo">The Nack Information structure to add</param> 00155 // public void Enqueue(NackInfo nackInfo) { 00156 // lock (this.SyncRoot) { 00157 // base.Enqueue(nackInfo); 00158 // } 00159 // } 00160 // 00161 // public new NackInfo Dequeue() { // this must not block and wait, because of where it's tested. 00162 // NackInfo result; 00163 // lock (this.SyncRoot) { 00164 // result = (NackInfo)base.Dequeue(); 00165 // } 00166 // return result; 00167 // } 00168 // 00169 // public bool IsEmpty { 00170 // get { 00171 // bool result; 00172 // lock (this.SyncRoot) { 00173 // result = (this.Count == 0); 00174 // } 00175 // return result; 00176 // } 00177 // } 00178 // } 00179 // 00180 // /*****************************************************************************/ 00181 // public class RetransmissionBuffer { 00182 // /* Contains a copy of every segment that may be requested by a 00183 // * negative acknowledgement. 00184 // * 00185 // * Data is indexed by segment number. Segment number and timestamp 00186 // * would have been better, but without adding another field to a 00187 // * segment we can not be sure of selecting the correct segment for 00188 // * retransmission. 00189 // * 00190 // * If a segment is retransmitted, it will not need to be re-transmitted again 00191 // * (the segment encapsulating the retransmission will be retransmitted). So we 00192 // * can erase the segment from the buffer when it is sent for retransmission. 00193 // * 00194 // * If segment m is such that all segments < m have been received, and m is a NACK 00195 // * requesting segment n, then we can retransmit 'n' and erase from the buffer 00196 // * all segments <= n. 00197 // * 00198 // * Let's just weaken this condition to 'if there are no missing segments'. 00199 // * This is the case where m is the segment just received. And to be honest, 00200 // * this is likely to be the case. 00201 // * 00202 // * Failure case: some segment > m is carrying a NACK for segment < n. 00203 // * This would occur if... there is no way this would occur. 00204 // * 00205 // * Note that all segments < m must have been received, not NACKd. 00206 // * 00207 // * As a failsafe we should have a 'Segment not in Buffer' message for problems. 00208 // * */ 00209 // /** fields **/ 00210 // Hashtable buffer; 00211 // private SequenceManager seqManager; 00212 // 00213 // /** properties */ 00214 // private uint earliestSegmentNumber { 00215 // get { 00216 // // TODO: Correct Min for wrapround error 00217 // lock (buffer.SyncRoot) { 00218 // ICollection keys = buffer.Keys; 00219 // uint[] keyArray = new uint[keys.Count]; 00220 // keys.CopyTo(keyArray, 0); 00221 // Array.Sort(keyArray); 00222 // return keyArray[0]; 00223 // } 00224 // } 00225 // } 00226 // 00227 // /** constructors **/ 00228 // public RetransmissionBuffer(SequenceManager seqManager) { 00229 // this.seqManager = seqManager; 00230 // buffer = new Hashtable(); 00231 // } 00232 // 00233 // /** methods**/ 00234 // /// <summary> 00235 // /// Called on Connection Reset to return retransmission buffer to initial state 00236 // /// </summary> 00237 // public void ResetConnection() { 00238 // lock (buffer.SyncRoot) { 00239 // buffer.Clear(); 00240 // } 00241 // } 00242 // 00243 // 00244 // /// <summary> 00245 // /// Adds segment 00246 // /// </summary> 00247 // private void Add(Segment target) { 00248 // lock (buffer.SyncRoot) { 00249 // buffer.Add(target.Headers.SequenceNumber, target); 00250 // } 00251 // 00252 // } 00253 // 00254 // /// <summary> 00255 // /// Removes a single segment based on segment number 00256 // /// </summary> 00257 // private void Remove(uint segmentNumber) { 00258 // lock (buffer.SyncRoot) { 00259 // buffer.Remove(segmentNumber); 00260 // } 00261 // } 00262 // 00263 // /// <summary> 00264 // /// Reads a segment from the Retransmission Buffer 00265 // /// </summary> 00266 // /// <returns>The segment requested</returns> 00267 // private Segment Read(uint segmentNumber) { 00268 // lock (buffer.SyncRoot) { 00269 // return (Segment)buffer[segmentNumber]; 00270 // } 00271 // } 00272 // 00273 // /// <summary> 00274 // /// Retrieves a segment from the buffer for retransmission, 00275 // /// and removes segments no longer needed 00276 // /// </summary> 00277 // /// <param name="nackSegmentHeaders">sequence number to retransmitt</param> 00278 // /// <returns>Segment to be retransmitted</returns> 00279 // public Segment GetSegment(uint sequenceNumber) { 00280 // lock (buffer.SyncRoot) { 00281 // Segment result = null; 00282 // 00283 // result = Read(sequenceNumber); 00284 // /* when we erase all segments 'less' than n, how do we identify them? They could wrap round, 00285 // * and thus some could be > n. Perhaps we should have a linked list type index structure? */ 00286 // /* or perhaps we should have some kind of 'earliest segment' indicator. */ 00287 // if (!seqManager.IsSegmentsMissing) { 00288 // // erase all segments less than nackSegmentHeaders.SequenceNumber 00289 // // i.e. all the ones that were put in before it. 00290 // if (earliestSegmentNumber > sequenceNumber) { 00291 // for (long i = sequenceNumber; i >= 0; i--) { 00292 // this.Remove((uint)i); } 00293 // for (long i = UInt32.MaxValue; i >= earliestSegmentNumber; i--) { 00294 // this.Remove((uint)i); } 00295 // } else { // earliestSegmentNumber <= nackSegmentHeaders.SequenceNumber 00296 // for (long i = sequenceNumber; i >= earliestSegmentNumber; i--) { 00297 // this.Remove((uint)i); } 00298 // } 00299 // } // else there are segments missing, so we can't erase anything for certain, so noop. 00300 // return result; 00301 // } 00302 // } 00303 // 00304 // /// <summary> 00305 // /// Inserts a segment into the retransmission buffer 00306 // /// </summary> 00307 // /// <param name="target">The segment object to insert</param> 00308 // public void PutSegment(Segment target) { 00309 // // todo: handle exceptions, etc. 00310 // lock (buffer.SyncRoot) { 00311 // this.Add(target); 00312 // } 00313 // } 00314 // 00315 // 00316 // } 00317 }