00001 using System;
00002 using System.Threading;
00003 using System.Collections;
00004 using System.Collections.Specialized;
00005 using Common;
00006
00007 namespace ProtocolStack
00008 {
00009
00010 public class ACKManager {
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 ACKManager(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;
00032 FIRST_ACKABLE_TIME = thisRemoteHost.thisStack.settings.FirstAckableTime;
00033 ACK_ARRIVAL_TIMEOUT = thisRemoteHost.thisStack.settings.AckArrivalTimeout;
00034 }
00035
00036 public void ResetConnection() {
00037 StopAckableGenerator();
00038 ackQueue.Clear();
00039 ackTimerList.ResetConnection();
00040 replyTracker.ResetConnection();
00041 StartAckableGenerator();
00042 }
00043
00048 public bool IsAckableWaiting() {
00049
00050
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
00064
00065 if (ackQueue.IsEmpty) { return null; }
00066 else return ackQueue.Dequeue();
00067 }
00068
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
00081 }
00082
00087 public void ProcessReceivedSegmentHeaders(ref SegmentHeaders headers) {
00088
00089
00090
00091 if (headers.IsAck) { this.SegmentAcknowledged(headers.ACKdSequenceNumber); }
00092 if (headers.IsAckable) { this.IssueACK(headers.SequenceNumber); }
00093 }
00094
00099 private void SegmentAcknowledged(uint ackdSequenceNumber) {
00100
00101
00102
00103
00104
00105 if (thisRemoteHost.readyToSendUserData) {
00106 if (ackTimerList.Contains(ackdSequenceNumber)) {
00107 ackTimerList.RemoveTimer(ackdSequenceNumber);
00108 replyTracker.ACKReceived();
00109
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
00120 lock(thisRemoteHost.TxQueue.SyncRoot) {
00121 if (thisRemoteHost.TxQueue.IsEmpty) {
00122
00123 Message noopMsg = new EmptyMessage();
00124 noopMsg.Destination = thisRemoteHost.RemoteDeviceID;
00125
00126 TransmissionQueueEntry[] buffer = TransmissionQueueEntry.FromMessage(noopMsg);
00127
00128
00129 thisRemoteHost.TxQueue.EnqueueUnprotected(buffer, false);
00130 }
00131 ackQueue.Enqueue(new AckInfo(sequenceNumberToACK));
00132
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
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
00160 Message noopMsg = new EmptyMessage();
00161 noopMsg.Destination = thisRemoteHost.RemoteDeviceID;
00162
00163 TransmissionQueueEntry[] buffer = TransmissionQueueEntry.FromMessage(noopMsg);
00164
00165
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;
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
00267
00268
00269 }
00270
00275 public void StartTheClock(uint countdown) {
00276 t.Change(countdown, Timeout.Infinite);
00277
00278 }
00279 }
00280
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
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
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
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
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
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
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 }