/*-------------------------------------------------------------------------- Project: HorizonSDK File: rdt_ResendQueue.cpp Copyright 2009 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2010-09-16#$ $Rev: 26004 $ $Author: hiratsu_daisuke $ *-------------------------------------------------------------------------*/ #include "stdafx.h" #include "rdt_ResendQueue.h" #include #include "Test.h" #include "rdt_Utility.h" namespace { } // end of anonymous namespace namespace nn { namespace rdt { namespace CTR { ResendQueue::ResendQueue(void) :m_bResendMode(false) { Clear(); } ResendQueue::~ResendQueue(void) { } bool ResendQueue::Push(const Segment &seg) { if(m_queue.IsFull()) { return false; } // TORIAEZU SegmentWithTime swt; swt.segment = seg; swt.timeStamp = nn::rdt::CTR::GetCurrentTimeAsMillisecond(); // データセグメントと違い、SYNセグメントはハイペースで送る必要はない。 if(seg.IsSyn()) { swt.timeOut = SYN_SEGMENT_TIMEOUT; } else { swt.timeOut = m_defaultTimeout; } if(!m_queue.IsEmpty()) { // 新しい実装では、タイムスタンプの半順序関係は // もはや保証できなくなっています(再送モードでは、半順序関係が崩れる) // しかし、その状態でこの関数が呼び出される(=再送処理が終わっていないのに、 // 新しいデータを送信しようとしている)のは問題であるので、このコードは // もう少し残しておきます。 // キューに記録されている要素群のタイムスタンプが半順序関係を // 保っているかどうかをチェックします。 ASSERT(swt.timeStamp >= m_queue.Back().timeStamp); } m_queue.PushBack(swt); return true; } bool ResendQueue::Front(Segment *pSeg) const { ASSERT(pSeg!=NULL); if(m_queue.IsEmpty()) { return false; } else { *pSeg = m_queue.Front().segment; return true; } } // TORIAEZU // Remove()については見直しが必要。もはやキューがタイムスタンプの順に並ぶことは // 仮定できなくなってしまっているから。 // この実装だと、Remove()対象がキューの先頭以外にある場合に、対象が除去されない。 void ResendQueue::Remove(u32 ack) { while(!m_queue.IsEmpty()) { const Segment &seg = m_queue.Front().segment; u32 lastSeq = seg.GetLastSeqNumber(); if(0 < static_cast(ack) - static_cast(lastSeq)) { m_queue.PopFront(); VERBOSE("再送キューの先頭を除去しました。\n"); if(m_queue.IsEmpty()) { // 再送キューをカラッポにしてしまったのならば、再送モードは終了。 m_bResendMode = false; } } else { // 先頭でさえACKによる到達確認が取れないのであれば、 // 後続のセグメントは言うに及ばす。ループを抜ける。 break; } } } bool ResendQueue::IsResendRequired(void) const { if(m_queue.IsEmpty()) { return false; } else { return m_queue.Front().IsTimeOut(); } } u32 ResendQueue::GetTotalDataSize(void) const { u32 ret = 0; for(size_t i= 0; i