/*-------------------------------------------------------------------------- Project: HorizonSDK File: rdt_ReceiverImpl.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-14#$ $Rev: 25753 $ $Author: hiratsu_daisuke $ *-------------------------------------------------------------------------*/ #include "stdafx.h" #include "rdt_ReceiverImpl.h" #include #include namespace { } // end of anonymous namespace namespace nn { namespace rdt { namespace CTR { // 「状態」の基底クラス。 class ReceiverStateBase{ public: virtual ~ReceiverStateBase(void){} virtual void initialize(ReceiverImpl *pReceiver); // この状態が開始されるときに呼ばれる virtual void finalize (ReceiverImpl *pReceiver); // この状態が終了されるときに呼ばれる virtual void update (ReceiverImpl *pReceiver); virtual enum ReceiverState getStatus(void) const = 0; protected: ReceiverStateBase(void){} }; void ReceiverStateBase::initialize(ReceiverImpl *pReceiver) { (void)pReceiver; } void ReceiverStateBase::finalize(ReceiverImpl *pReceiver) { (void)pReceiver; } void ReceiverStateBase::update(ReceiverImpl *pReceiver) { (void)pReceiver; } class ReceiverStateWaiting : public ReceiverStateBase{ public: static ReceiverStateBase* getInstance(void); virtual void update(ReceiverImpl *pReceiver); virtual enum ReceiverState getStatus(void) const; protected: ReceiverStateWaiting(void){} }; class ReceiverStateOpened : public ReceiverStateBase{ public: static ReceiverStateBase* getInstance(void); virtual void update(ReceiverImpl *pReceiver); virtual enum ReceiverState getStatus(void) const; protected: ReceiverStateOpened(void){} }; class ReceiverStateWaitingFinished : public ReceiverStateBase{ public: static ReceiverStateBase* getInstance(void); virtual void update(ReceiverImpl *pReceiver); virtual enum ReceiverState getStatus(void) const; protected: ReceiverStateWaitingFinished(void){} }; class ReceiverStateFinished : public ReceiverStateBase{ public: static ReceiverStateBase* getInstance(void); virtual void update(ReceiverImpl *pReceiver); virtual enum ReceiverState getStatus(void) const; protected: ReceiverStateFinished(void){} }; class ReceiverStateClosed : public ReceiverStateBase{ public: static ReceiverStateBase* getInstance(void); virtual void initialize(ReceiverImpl *pReceiver); virtual void update (ReceiverImpl *pReceiver); virtual enum ReceiverState getStatus(void) const; protected: ReceiverStateClosed(void){} }; // 以下、派生クラスの実装。 ReceiverStateBase* ReceiverStateWaiting::getInstance(void) { static ReceiverStateWaiting s_instance; return &s_instance; } enum ReceiverState ReceiverStateWaiting::getStatus(void) const { return RECEIVER_STATE_WAITING; } void ReceiverStateWaiting::update(ReceiverImpl *pReceiver) { ASSERT(pReceiver!=NULL); //セグメントを受信していれば、ここで処理。 Segment seg; if(pReceiver->pullSegment(&seg).IsSuccess()) { if(seg.IsRst()) { // TCPのRFCによると、LISTEN状態の時に受信したRSTは // 無視すべき、との記述があった。よって、ここでは何もしない。 } else if(seg.IsSyn()) { // リモートからの正しい接続要求であれば、ACKを返す。 // 受信バッファの設定 pReceiver->m_recvBuf.SetInitialSequenceNumber(seg.GetSeqNumber()); // SYNへの応答。 pReceiver->putSynAckSegment(seg.GetSeqNumber() + 1); pReceiver->setNextState(ReceiverStateOpened::getInstance()); } } } ReceiverStateBase* ReceiverStateOpened::getInstance(void) { static ReceiverStateOpened s_instance; return &s_instance; } enum ReceiverState ReceiverStateOpened::getStatus(void) const { return RECEIVER_STATE_OPENED; } void ReceiverStateOpened::update(ReceiverImpl *pReceiver) { ASSERT(pReceiver!=NULL); //セグメントを受信していれば、ここで処理。 Segment seg; if(pReceiver->pullSegment(&seg).IsSuccess()) { // まずはRSTビットチェック if(seg.IsRst()) { pReceiver->setNextState(ReceiverStateClosed::getInstance()); pReceiver->errorHandling(ResultResetReceived()); return; } // 期待しているシーケンス番号のセグメントが到着しているか? ReceiveBuffer &rBuf = pReceiver->m_recvBuf; if(seg.GetSeqNumber()==rBuf.GetLatestSequenceNumber()+1) { if(seg.IsData()) { bool result = rBuf.Push(seg.payload, seg.GetDataLength()); if(result) { // データを無事に受信バッファに格納できた。 // 従来の実装ではACKを返していたが、それでは受信側のACKパケットばかりになってしまう。 // そこで、ここでACKを返すのはやめた。 } else { LOG("Received data segment, but could not return ACK because receive buffer did not have enough space.\n"); } } else if(seg.IsFin()) { // FINセグメントに対するACK送信 pReceiver->putFinAckSegment(seg.GetSeqNumber() + 1); pReceiver->setNextState(ReceiverStateWaitingFinished::getInstance()); } else { seg.PrintDebugInfo(); PANIC("It seems that SEQ number is valid, but unexpected segment. It is not DATA, nor FIN."); } } else if(seg.GetSeqNumber()==rBuf.GetLatestSequenceNumber()) { // Synに対する応答が届かなかった場合に、SenderはSyn要求を再送することが考えられる。 // その場合の対処。 if(seg.IsSyn()) { // SYNへの応答。 pReceiver->putSynAckSegment(seg.GetSeqNumber() + 1); } } else { VERBOSE("Unexpected SEQ number. (%d)\n", seg.GetSeqNumber()); VERBOSE("SEQ number %d is expected.\n", rBuf.GetLatestSequenceNumber()+1); VERBOSE("Received segment will be ignored.\n"); #if 0 // 期待していないセグメントだったので、パケロスの可能性が疑われる。 // ひとまず今まで受信できた分には速やかにACKを返す。 pReceiver->putAckSegment(); // ↑このコードを入れると、返って遅くなってしまった。ACKパケットが大量発生したからだろうか… #endif } } } ReceiverStateBase* ReceiverStateWaitingFinished::getInstance(void) { static ReceiverStateWaitingFinished s_instance; return &s_instance; } enum ReceiverState ReceiverStateWaitingFinished::getStatus(void) const { return RECEIVER_STATE_WAITING_FINISHED; } void ReceiverStateWaitingFinished::update(ReceiverImpl *pReceiver) { // こちらがFINに対するACKを返し、Finished状態になったとしても、 // そのACKが向こうに届いているとは限らない。 // ACKが向こうに届いたと判断するためには、ある程度の時間をおき、 // 向こうから再送パケットが届かなくなることを確認する必要がある。 ASSERT(pReceiver!=NULL); //セグメントを受信していれば、ここで処理。 Segment seg; if(pReceiver->pullSegment(&seg).IsSuccess()) { // RSTビットチェック if(seg.IsRst()) { pReceiver->setNextState(ReceiverStateClosed::getInstance()); pReceiver->errorHandling(ResultResetReceived()); return; } // FINのセグメントが到着しているか? ReceiveBuffer &rBuf = pReceiver->m_recvBuf; if(seg.GetSeqNumber()==rBuf.GetLatestSequenceNumber()+1) { if(seg.IsFin()) { pReceiver->putFinAckSegment(seg.GetSeqNumber() + 1); } else { seg.PrintDebugInfo(); PANIC("Sequence number is valid, but FIN is not included.\n"); } } else { // seg.PrintDebugInfo(); LOG("Segment with unexpected sequence number. Ignored.\n"); } } // タイムアウト判定をしてから、状態遷移。 if(pReceiver->isSenderClosed()) { pReceiver->setNextState(ReceiverStateFinished::getInstance()); } } ReceiverStateBase* ReceiverStateFinished::getInstance(void) { static ReceiverStateFinished s_instance; return &s_instance; } enum ReceiverState ReceiverStateFinished::getStatus(void) const { return RECEIVER_STATE_FINISHED; } void ReceiverStateFinished::update(ReceiverImpl *pReceiver) { ASSERT(pReceiver!=NULL); //セグメントを受信していれば、ここで処理。 Segment seg; if(pReceiver->pullSegment(&seg).IsSuccess()) { // TODO: RSTを含まないセグメントに対しては、RSTを送信すべき。 PANIC("State is FINISHED, but received segment from remote!\n"); } } ReceiverStateBase* ReceiverStateClosed::getInstance(void) { static ReceiverStateClosed s_instance; return &s_instance; } enum ReceiverState ReceiverStateClosed::getStatus(void) const { return RECEIVER_STATE_CLOSED; } void ReceiverStateClosed::initialize(ReceiverImpl *pReceiver) { ASSERT(pReceiver!=NULL); pReceiver->clear(); } void ReceiverStateClosed::update(ReceiverImpl *pReceiver) { ASSERT(pReceiver!=NULL); // CLOSED状態の時に受信した(RSTを含まない)セグメントに対しては、RSTで返答 Segment seg; if(pReceiver->pullSegment(&seg).IsSuccess() && !seg.IsRst()) { LOG("Receiver is in CLOSED state, but received segment. RST will be sent.\n"); if(seg.IsAck()) { pReceiver->sendRstSegment(seg.GetAckNumber()); } else { const u32 SEQ = 0; const u32 ACK = seg.GetSeqNumber() + seg.GetSegmentLength(); pReceiver->sendRstAckSegment(SEQ, ACK); } } } ///< コンストラクタ ReceiverImpl::ReceiverImpl(void) throw() :m_initialized(false) { } ///< デストラクタ ReceiverImpl::~ReceiverImpl(void) { Finalize(); } #ifdef _WIN32 nn::Result ReceiverImpl::Initialize(SOCKET sock, void *pRecvBuf, u16 recvBufSize) #else nn::Result ReceiverImpl::Initialize(u16 nodeId, u8 port, void *pRecvBuf, u16 recvBufSize) #endif { if(m_initialized) { return ResultAlreadyInitialized(); } else { if(pRecvBuf==NULL) { return ResultNullPointer(); } if(recvBufSize==0) { return ResultInvalidSize(); } #ifdef _WIN32 nn::Result result = HostBase::Initialize(sock); #elif defined(NN_PLATFORM_CTR) nn::Result result = HostBase::Initialize(nodeId, port); #endif if(result.IsFailure()) { return result; } else { m_pState = ReceiverStateClosed::getInstance(); m_pNextState = NULL; m_recvBuf.Initialize(pRecvBuf, recvBufSize); clear(); m_initialized = true; return ResultSuccess(); } } } void ReceiverImpl::Finalize(void) { if(m_initialized) { m_initialized = false; m_recvBuf.Finalize(); HostBase::Finalize(); } else { // Do nothing. } } nn::Result ReceiverImpl::Wait(void) { ASSERT(m_initialized); if(GetStatus()==RECEIVER_STATE_CLOSED) { setNextState(ReceiverStateWaiting::getInstance()); changeState(); return ResultSuccess(); } else { return ResultUntimelyFunctionCall(); } } nn::Result ReceiverImpl::Close(void) { ASSERT(m_initialized); if(GetStatus()==RECEIVER_STATE_FINISHED) { setNextState(ReceiverStateClosed::getInstance()); changeState(); return ResultSuccess(); } else { return ResultUntimelyFunctionCall(); } } nn::Result ReceiverImpl::Receive(void *pBuf, size_t *recvSize, size_t bufSize) { ASSERT(m_initialized); if((pBuf==NULL) || (recvSize==NULL)) { return ResultNullPointer(); } if(bufSize==0) { return ResultDoNothing(); } enum ReceiverState stat = GetStatus(); if((stat!=RECEIVER_STATE_OPENED) && (stat!=RECEIVER_STATE_WAITING_FINISHED) && (stat!=RECEIVER_STATE_FINISHED)) { return ResultUntimelyFunctionCall(); } *recvSize = m_recvBuf.Read(pBuf, bufSize); if(*recvSize > 0) { m_recvBuf.Pop(*recvSize); } // Receiveをトリガーにして、リモートにウィンドウを通知する。 // 受信ウィンドウに空きができたので、リモートに通知する目的でセグメントを送信する。 // OPENED状態でないときにセグメントを送ろうとすると、接続が断絶している可能性があるので、 // if文による状態チェックを行っている。 if(GetStatus()==RECEIVER_STATE_OPENED) { putAckSegment(); } return ResultSuccess(); } nn::Result ReceiverImpl::Process(void) { ASSERT(m_initialized); // 各状態のupdate()。 if(m_pState) { m_pState->update(this); } // 状態遷移 changeState(); // エラーはここで返る。 // 返したら、エラーはリセットする。 nn::Result ret = GetErrorCode(); errorHandling(ResultSuccess()); return ret; } enum ReceiverState ReceiverImpl::GetStatus(void) const { ASSERT(m_initialized); ASSERTMSG(m_pState!=NULL, "It seems that state is not initialized.\n"); return m_pState->getStatus(); } void ReceiverImpl::Cancel(void) { ASSERT(m_initialized); // キャンセル処理は、Process()関数を待たずに即座に実行させる。 // RST送信 const u32 seq = 0; sendRstSegment(seq); // 即座にClosed状態へ。 setNextState(ReceiverStateClosed::getInstance()); changeState(); } // 状態遷移。次の状態がセットされていないなら、特に何もしない。 void ReceiverImpl::changeState(void) { if(m_pNextState) { if(m_pState) { m_pState->finalize(this); } m_pState = m_pNextState; m_pNextState = NULL; m_pState->initialize(this); } } void ReceiverImpl::setNextState(ReceiverStateBase *p) { ASSERT(p!=NULL); ASSERT(m_pNextState==NULL); m_pNextState = p; } void ReceiverImpl::putSynAckSegment(u32 ack) { Segment a; a.ClearHeader(); a.SetAckNumber(ack); a.SetWindowSize(m_recvBuf.GetRestSize()); putSegment(a); } void ReceiverImpl::putAckSegment(void) { Segment a; a.ClearHeader(); a.SetAckNumber(m_recvBuf.GetLatestSequenceNumber()+1); a.SetWindowSize(m_recvBuf.GetRestSize()); putSegment(a); } void ReceiverImpl::putFinAckSegment(u32 ack) { Segment a; a.ClearHeader(); a.SetAckNumber(ack); a.SetWindowSize(m_recvBuf.GetRestSize()); putSegment(a); m_finAckSentTime = GetCurrentTimeAsMillisecond(); } bool ReceiverImpl::isSenderClosed(void) const { ASSERT(m_finAckSentTime!=0); // LOG("m_finAckSentTime = %lld\n", m_finAckSentTime); // LOG("Current: %lld\n", GetCurrentTimeAsMillisecond()); return GetCurrentTimeAsMillisecond() - m_finAckSentTime > FIN_TIMEOUT; } void ReceiverImpl::clear(void) { m_recvBuf.Clear(); m_finAckSentTime = 0; } void ReceiverImpl::PrintDebugInfo(void) const { LOG("-- Receiver debug information --\n"); LOG("Current state: %d\n", GetStatus()); m_recvBuf.PrintDebugInfo(); LOG("\n"); } }}} // namespace nn::rdt::CTR