00001 using System; 00002 using System.Threading; 00003 using System.Collections; 00004 using System.Collections.Specialized; 00005 00006 namespace SmartDeviceGUIClient 00007 { 00008 public class ACKManager{} 00009 00010 // public class ACKManager2 { 00011 // public static int INTER_ACKABLE_TIME; 00012 // public static int FIRST_ACKABLE_TIME; 00013 // public static int ACK_ARRIVAL_TIMEOUT; 00014 // 00015 // private AckQueue ackQueue; 00016 // private ReplyTracker replyTracker; 00017 // private AckTimerList ackTimerList; 00018 // private AckableGenerator ackableGenerator; 00019 // private RemoteHostComms thisRemoteHost; 00020 // 00021 // public ACKManager2(RemoteHostComms thisRemoteHost) { 00022 // this.thisRemoteHost = thisRemoteHost; 00023 // Init(); 00024 // ackQueue = new AckQueue(); 00025 // replyTracker = new ReplyTracker(); 00026 // ackTimerList = new AckTimerList(replyTracker, thisRemoteHost.thisStack.connectionReset); 00027 // ackableGenerator = new AckableGenerator(thisRemoteHost); 00028 // } 00029 // 00030 // public void Init() { 00031 // INTER_ACKABLE_TIME = thisRemoteHost.thisStack.settings.InterAckableTime; // seconds 00032 // FIRST_ACKABLE_TIME = thisRemoteHost.thisStack.settings.FirstAckableTime; // seconds 00033 // ACK_ARRIVAL_TIMEOUT = thisRemoteHost.thisStack.settings.AckArrivalTimeout; // seconds 00034 // } 00035 // 00036 // public void ResetConnection() { 00037 // StopAckableGenerator(); 00038 // ackQueue.Clear(); 00039 // ackTimerList.ResetConnection(); 00040 // replyTracker.ResetConnection(); 00041 // StartAckableGenerator(); 00042 // } 00043 // 00044 // /// <summary> 00045 // /// Determines if the next segment to be sent should be 'ackable' 00046 // /// </summary> 00047 // /// <returns></returns> 00048 // public bool IsAckableWaiting() { 00049 // /* if we are due to send an ackable packet, this will return true. Else it will not. 00050 // * should maintain a count of ackable packets waiting (semaphore style?) */ 00051 // return ackableGenerator.IsAckableWaiting; 00052 // } 00053 // 00054 // public void StartAckableGenerator() { 00055 // ackableGenerator.Start(); 00056 // } 00057 // 00058 // public void StopAckableGenerator() { 00059 // ackableGenerator.Stop(); 00060 // } 00061 // 00062 // public AckInfo GetNextAck() { 00063 // /* returns details of the next acknowledgement that needs to be sent, 00064 // * or null if no acknowledgement needs sending */ 00065 // if (ackQueue.IsEmpty) { return null; } 00066 // else return ackQueue.Dequeue(); 00067 // } 00068 // 00069 // /// <summary> 00070 // /// Sets timer awaiting arrival of the acknowledgemnt for just sent ackable packet. 00071 // /// </summary> 00072 // /// <param name="sequenceNumber">sequence number we are expecting an ACK for</param> 00073 // public void SentAckableSegment(uint sequenceNumber) { 00074 // ackableGenerator.DecAckablesWaiting(); 00075 // if (thisRemoteHost.readyToSendUserData) { 00076 // ackTimerList.AddTimer(sequenceNumber); 00077 // } else { 00078 // Console.WriteLine(" Did not set timer for return of ACK, since not ready to send"); 00079 // } 00080 // //Console.WriteLine("ACK Manager: Ackable Segment #" + sequenceNumber +" just Sent"); 00081 // } 00082 // 00083 // /// <summary> 00084 // /// Issues and accepts acknowledgements from a set of Segment Headers 00085 // /// </summary> 00086 // /// <param name="headers">Segment Headers to process</param> 00087 // public void ProcessReceivedSegmentHeaders(ref SegmentHeaders headers) { 00088 // /* if segment is an ACK, call SegmentAcknowledged(seqNum) 00089 // * if segment is ACKable, call IssueACK(seqNum) 00090 // * otherwise noop*/ 00091 // if (headers.IsAck) { this.SegmentAcknowledged(headers.ACKdSequenceNumber); } 00092 // if (headers.IsAckable) { this.IssueACK(headers.SequenceNumber); } 00093 // } 00094 // 00095 // /// <summary> 00096 // /// Processes the acknowledgement of a segment. 00097 // /// </summary> 00098 // /// <param name="ackdSequenceNumber">The segment number that has been acknowledged</param> 00099 // private void SegmentAcknowledged(uint ackdSequenceNumber) { 00100 // /* If a timer for the segment has not yet expired: 00101 // * - clear the timer 00102 // * - reset the 'Number of Acks missed in a row' counter 00103 // * else 00104 // * - do nothing */ 00105 // if (thisRemoteHost.readyToSendUserData) { 00106 // if (ackTimerList.Contains(ackdSequenceNumber)) { 00107 // ackTimerList.RemoveTimer(ackdSequenceNumber); 00108 // replyTracker.ACKReceived(); 00109 // //Console.WriteLine("ACK Manager: ACK received for segment#" + ackdSequenceNumber); 00110 // } 00111 // } else { 00112 // thisRemoteHost.readyToSendUserData = true; 00113 // Console.WriteLine("### First ACK received. Now READY TO SEND USER DATA ###"); 00114 // } 00115 // 00116 // } 00117 // 00118 // private void IssueACK(uint sequenceNumberToACK) { 00119 // //Console.WriteLine("ACK Manager: Ackable received. Need to ACK #" + sequenceNumberToACK); 00120 // lock(thisRemoteHost.TxQueue.SyncRoot) { 00121 // if (thisRemoteHost.TxQueue.IsEmpty) { 00122 // /* create no-op message */ 00123 // Message noopMsg = new EmptyMessage(); 00124 // noopMsg.Destination = thisRemoteHost.RemoteDeviceID; 00125 // /* segmentise */ 00126 // TransmissionQueueEntry[] buffer = TransmissionQueueEntry.FromMessage(noopMsg); 00127 // /* place results in segment queue */ 00128 // // make sure this all happens in a monitor, so we get them all together 00129 // thisRemoteHost.TxQueue.EnqueueUnprotected(buffer, false); 00130 // } 00131 // ackQueue.Enqueue(new AckInfo(sequenceNumberToACK)); 00132 // //Console.WriteLine("ACK Manager: ACK Issued for #" + sequenceNumberToACK); 00133 // Monitor.PulseAll(thisRemoteHost.TxQueue.SyncRoot); 00134 // } 00135 // 00136 // } 00137 // } 00138 // 00139 // public class AckableGenerator { 00140 // private int ackablesWaitingCount; 00141 // private Timer ackableGenerateTimer; 00142 // private RemoteHostComms thisRemoteHost; 00143 // private TransmissionQueue txQueue; 00144 // 00145 // /// <summary> 00146 // /// Creates a new generator of Ackable segments 00147 // /// </summary> 00148 // /// <param name="txQueue">The transmission queue to output carriers on to, if need be</param> 00149 // public AckableGenerator(RemoteHostComms thisRemoteHost) { 00150 // this.thisRemoteHost = thisRemoteHost; 00151 // this.txQueue = thisRemoteHost.TxQueue; 00152 // ackablesWaitingCount = 0; 00153 // ackableGenerateTimer = new Timer(new TimerCallback(this.GeneratorTimerCallback), null, Timeout.Infinite, Timeout.Infinite); 00154 // } 00155 // 00156 // public void GeneratorTimerCallback(object o) { 00157 // lock(txQueue.SyncRoot) { 00158 // if (txQueue.IsEmpty) { 00159 // /* create no-op message */ 00160 // Message noopMsg = new EmptyMessage(); 00161 // noopMsg.Destination = thisRemoteHost.RemoteDeviceID; 00162 // /* segmentise */ 00163 // TransmissionQueueEntry[] buffer = TransmissionQueueEntry.FromMessage(noopMsg); 00164 // /* place results in segment queue */ 00165 // // make sure this all happens in a monitor, so we get them all together 00166 // txQueue.EnqueueUnprotected(buffer, false); 00167 // } 00168 // IncAckablesWaiting(); 00169 // lock (thisRemoteHost.AckManager) { 00170 // Monitor.PulseAll(thisRemoteHost.AckManager); 00171 // } 00172 // Monitor.PulseAll(txQueue.SyncRoot); 00173 // } 00174 // } 00175 // 00176 // public void IncAckablesWaiting() { 00177 // lock(this) { 00178 // ackablesWaitingCount++; 00179 // } 00180 // } 00181 // public void DecAckablesWaiting() { 00182 // lock(this) { 00183 // if (ackablesWaitingCount > 0) { ackablesWaitingCount--; } 00184 // } 00185 // } 00186 // 00187 // public void ResetConnection() { 00188 // lock(this) { 00189 // ackablesWaitingCount = 0; 00190 // } 00191 // } 00192 // 00193 // public void Start() { 00194 // ackableGenerateTimer.Change(ACKManager.FIRST_ACKABLE_TIME * 1000, ACKManager.INTER_ACKABLE_TIME * 1000); 00195 // } 00196 // 00197 // public void Stop() { 00198 // ackableGenerateTimer.Change(Timeout.Infinite, Timeout.Infinite); 00199 // } 00200 // 00201 // public bool IsAckableWaiting { 00202 // get { 00203 // bool result; 00204 // lock(this) { 00205 // result = (ackablesWaitingCount != 0); 00206 // } 00207 // return result; 00208 // } 00209 // } 00210 // 00211 // } 00212 00213 public class AckInfo { 00215 uint sequenceNumber; // seq # of the segment that needs acking 00216 00218 public AckInfo(uint sequenceNumber) { 00219 this.sequenceNumber = sequenceNumber; 00220 } 00221 00223 public uint SequenceNumber { get { return sequenceNumber; } } 00224 } 00225 00226 // class AckQueue : Queue { 00227 // public AckQueue() : base() {} 00228 // 00229 // public void Enqueue(AckInfo ackInfo) { 00230 // lock (this.SyncRoot) { 00231 // base.Enqueue(ackInfo); 00232 // Monitor.PulseAll(this.SyncRoot); 00233 // } 00234 // } 00235 // 00236 // public new AckInfo Dequeue() { 00237 // AckInfo result; 00238 // lock (this.SyncRoot) { 00239 // result = (AckInfo)base.Dequeue(); 00240 // } 00241 // return result; 00242 // } 00243 // 00244 // 00245 // public bool IsEmpty { 00246 // get { 00247 // bool result; 00248 // lock (this.SyncRoot) { 00249 // result = (this.Count == 0); 00250 // } 00251 // return result; 00252 // } 00253 // } 00254 // 00255 // } 00256 // 00257 // class AckTimer { 00258 // private Timer t; 00259 // 00260 // public AckTimer(TimerInfo timerInfo, TimerCallback callback) { 00261 // t = new Timer(callback, timerInfo, Timeout.Infinite, Timeout.Infinite); 00262 // } 00263 // 00264 // public void StopTheClock() { 00265 // t.Change(Timeout.Infinite, Timeout.Infinite); 00266 // //t.Dispose(); 00267 // //t = null; // cause garbage collecter to free some memory. 00268 // //Console.WriteLine("Clock Stopped"); 00269 // } 00270 // 00271 // /// <summary> 00272 // /// Starts the timer. 'TimerExpired' will execute after the number of milliseconds in the argument 00273 // /// </summary> 00274 // /// <param name="countdown">Number of milliseconds before timer expires</param> 00275 // public void StartTheClock(uint countdown) { 00276 // t.Change(countdown, Timeout.Infinite); 00277 // //Console.WriteLine("Clock Started"); 00278 // } 00279 // } 00280 // 00281 // /// <summary> 00282 // /// Maintains a list of the number of ACKs that have been missed in succession. 00283 // /// Must be locked before use. 00284 // /// </summary> 00285 // class ReplyTracker { 00286 // private int noReplyCount; 00287 // public ReplyTracker() { 00288 // Init(); 00289 // } 00290 // 00291 // private void Init() { 00292 // noReplyCount = 0; 00293 // } 00294 // 00295 // public void ResetConnection() { 00296 // Init(); 00297 // } 00298 // 00299 // public void ACKMissed() { 00300 // noReplyCount++; 00301 // if (noReplyCount == 3) { 00302 // throw new ConnectionReset(); 00303 // } 00304 // } 00305 // 00306 // public void ACKReceived() { 00307 // noReplyCount = 0; 00308 // } 00309 // } 00310 // 00311 // /// <summary> 00312 // /// List of AckTimers. Also deals with the 'three strikes and you're out' connection reset. 00313 // /// </summary> 00314 // class AckTimerList : ListDictionary { 00315 // private ReplyTracker replyTracker; 00316 // private ConnectionResetDelegate connectionReset; 00317 // 00318 // public AckTimerList(ReplyTracker replyTracker, ConnectionResetDelegate connectionReset) : base() { 00319 // this.replyTracker = replyTracker; 00320 // this.connectionReset = connectionReset; 00321 // } 00322 // 00323 // /// <summary> 00324 // /// Adds a timer to the list for a the ACK of a given sequence number. 00325 // /// Sets it going on a 10 second fuse 00326 // /// </summary> 00327 // /// <param name="sequenceNumber">sequence number we are timing the ACK response for</param> 00328 // public void AddTimer(uint sequenceNumber) { 00329 // TimerInfo info = new TimerInfo(sequenceNumber, replyTracker); 00330 // AckTimer timerObj = new AckTimer(info, new TimerCallback(this.TimerExpires)); 00331 // base.Add(sequenceNumber, timerObj); 00332 // timerObj.StartTheClock((uint)ACKManager.ACK_ARRIVAL_TIMEOUT * 1000); 00333 // } 00334 // 00335 // /// <summary> 00336 // /// Called by timer thread when a timer expires. 00337 // /// </summary> 00338 // /// <param name="obj">A TimerInfo object telling what segment number we were wating for, and where to record the count</param> 00339 // public void TimerExpires(object obj){ 00340 // try { 00341 // TimerInfo ti = (TimerInfo)obj; 00342 // lock(ti.tracker) { 00343 // ti.tracker.ACKMissed(); 00344 // } 00345 // this.RemoveTimer(ti.segmentNumber); 00346 // } catch (ConnectionReset) { 00347 // Console.WriteLine("*** No traffic on connection for last 90 seconds. Connection Reset ***\n*** Calling Connection Reset Handler ***"); 00348 // connectionReset(); 00349 // } 00350 // } 00351 // 00352 // /// <summary> 00353 // /// Stops timer for given sequence number, and removes it from the list. 00354 // /// </summary> 00355 // /// <param name="sequenceNumber"></param> 00356 // public void RemoveTimer(uint sequenceNumber) { 00357 // AckTimer workingTimer = (AckTimer)base[sequenceNumber]; 00358 // if (workingTimer != null) { 00359 // workingTimer.StopTheClock(); 00360 // } 00361 // base.Remove(sequenceNumber); 00362 // } 00363 // 00364 // /// <summary> 00365 // /// Stops and removes all timers 00366 // /// </summary> 00367 // public void ResetConnection() { 00368 // foreach (DictionaryEntry de in this) { 00369 // AckTimer timer = (AckTimer)de.Value; 00370 // timer.StopTheClock(); 00371 // } 00372 // Clear(); 00373 // } 00374 // } 00375 // 00376 // /// <summary> 00377 // /// An object passed to the timer, which in turn passes it to the timer callback on firing. 00378 // /// This object specifies where to find the ReplyTracker object, and what segement number we were wating for 00379 // /// (this allows is to delete the timer) 00380 // /// </summary> 00381 // class TimerInfo { 00382 // public uint segmentNumber; 00383 // public ReplyTracker tracker; 00384 // 00385 // public TimerInfo(uint segmentNumber, ReplyTracker tracker) { 00386 // this.segmentNumber = segmentNumber; 00387 // this.tracker = tracker; 00388 // } 00389 // } 00390 }