/*-------------------------------------------------------------------------- Project: HorizonSDK File: rdt_ReceiverImpl.h 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-13#$ $Rev: 25720 $ $Author: hiratsu_daisuke $ *-------------------------------------------------------------------------*/ #include "stdafx.h" #ifndef NN_RDT_RECEIVERIMPL_H_ #define NN_RDT_RECEIVERIMPL_H_ #include "rdt_HostBase.h" #include "rdt_ReceiveBuffer.h" #include "rdt_Segment.h" namespace nn { namespace rdt { namespace CTR { // 先行宣言 class ReceiverStateBase; /*! @brief これはReceiverクラスの内部実装のためのクラスです。 */ class ReceiverImpl : public HostBase{ public: /*! @brief コンストラクタです。初期化フラグを下ろす以外のことはしません。 */ ReceiverImpl(void) throw(); /*! @brief デストラクタです。 */ virtual ~ReceiverImpl(void); /*! @brief 初期化します。 */ #ifdef _WIN32 nn::Result Initialize(SOCKET sock, void *pRecvBuf, u16 recvBufSize); #elif defined(NN_PLATFORM_CTR) nn::Result Initialize(u16 nodeId, u8 port, void *pRecvBuf, u16 recvBufSize); #endif /*! @brief 解放します。 */ void Finalize(void); /*! @brief Senderが接続しにくるのを待つリクエストを発行します。 */ nn::Result Wait(void); /*! @brief データを全て受信した後で呼ぶことを想定されています。 オブジェクトの状態がCLOSED状態に戻り、再利用できるようになります。 */ nn::Result Close(void); /*! @brief ライブラリの受信バッファに溜められたデータを読み取ります。 成功した場合、読み取ったバイト数がrecvSizeに記録されます。 読み取るデータが1バイトも存在していなかった場合は、recvSizeにゼロが書き込まれます。 */ nn::Result Receive(void *pBuf, size_t *recvSize, size_t bufSize); /*! @brief 通信処理を進行させます。実際の通信処理は、この関数の内部で実行されます。 アプリ側から、毎フレーム程度の間隔で呼び出してもらうことを想定しています。 一連の処理において、何らかのエラーがあった場合はエラーが返ります。 */ nn::Result Process(void); /*! @brief 処理の中断をリクエストします。 */ void Cancel(void); /*! @brief Receiverインスタンスの状態を取得します。 */ enum ReceiverState GetStatus(void) const; /*! @brief 配置new演算子です。 */ static void* operator new(size_t size, void *pBuf) throw() { if(size!=sizeof(ReceiverImpl)) { PANIC("Wrong size.\n"); return NULL; } if(pBuf==NULL) { PANIC("NULL pointer is detected.\n"); return NULL; } ALIGN_ASSERT(pBuf, 8); return pBuf; } static void operator delete (void *p) throw() { PANIC("Do not call this delete! Please call destructor manually.\n"); (void)p; } /*! @brief このオブジェクトの詳細な内部状態をプリントします。(デバッグ用) */ void PrintDebugInfo(void) const; private: /*! @brief コピーコンストラクタは封印します。 */ ReceiverImpl (const ReceiverImpl&); /*! @brief 代入演算子は封印します。 */ ReceiverImpl& operator=(const ReceiverImpl&); // 定数 static const MSEC_T FIN_TIMEOUT = 1000; // TORIAEZU。CTR実機で要調整のパラメータ。 // プライベート関数群。 void changeState(void); // この関数を呼ぶことで、状態遷移が実行される。 void setNextState(ReceiverStateBase *p); // 次の状態をセット。 // SYNに対する応答を作成する際に呼ぶ。 void putSynAckSegment(u32 ack); // ACKのセグメントを作る際に呼ぶ。 void putAckSegment(void); // FINに対するACKのセグメントを送信する際に呼ぶ。 // このとき、ACK送信時刻も記録される。 void putFinAckSegment(u32 ack); // FINに対するACKを送ってから十分な時間が経ち、相手は // クローズしたと確信できるか? bool isSenderClosed(void) const; // 受信バッファはカラッポか? bool isReceiveBufferEmpty(void) const { return m_recvBuf.IsEmpty(); } // Closed状態に入るときなどに呼ばれることを想定。 // Stateパターンにおける状態を保持するメンバを除き、 // 各種メンバ変数をまっさらな状態に戻す。 void clear(void); // メンバ変数群。 ReceiveBuffer m_recvBuf; // 受信バッファ。Senderからやってきた実データはここに格納される。 bool m_initialized; // 初期化済み? u8 m_padding[7]; // MSEC_T型が64bitであることに注意! MSEC_T m_finAckSentTime; // 最後にFINセグメントに対するACKを送信したときの時刻。 // Stateパターンの実践。 ReceiverStateBase *m_pState; ReceiverStateBase *m_pNextState; friend class ReceiverStateWaiting; friend class ReceiverStateOpened; friend class ReceiverStateWaitingFinished; friend class ReceiverStateFinished; friend class ReceiverStateClosed; }; }}} // namespace nn::rdt::CTR #endif // end of NN_RDT_RECEIVERIMPL_H_