1 /*--------------------------------------------------------------------------
2   Project:  HorizonSDK
3   File:     rdt_SenderImpl.h
4 
5   Copyright 2009 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2010-09-13#$
14   $Rev: 25720 $
15   $Author: hiratsu_daisuke $
16  *-------------------------------------------------------------------------*/
17 
18 #include "stdafx.h"
19 
20 #ifndef NN_RDT_SENDERIMPL_H_
21 #define NN_RDT_SENDERIMPL_H_
22 
23 #include "rdt_HostBase.h"
24 #include "rdt_SendBuffer.h"
25 #include "rdt_ResendQueue.h"
26 #include "rdt_Segment.h"
27 
28 namespace nn { namespace rdt { namespace CTR {
29 
30 // 先行宣言
31 class SenderStateBase;
32 
33 
34 /*!
35     @brief これはSenderクラスの内部実装のためのクラスです。
36 */
37 class SenderImpl : public HostBase{
38 public:
39 /*!
40     @brief 初期化します。
41 */
42     SenderImpl(void) throw();
43 
44 /*!
45     @brief デストラクタです。仮にFinalize()が呼ばれていなくても、この中で自動的に呼び出されます。
46 */
47    virtual ~SenderImpl(void);
48 
49 /*!
50     @brief 初期化します。
51 */
52 #ifdef _WIN32
53     nn::Result Initialize(SOCKET sock, void *pSendBuf, u16 sendBufSize);
54 #elif defined(NN_PLATFORM_CTR)
55     nn::Result Initialize(u16 nodeId, u8 port, void *pSendBuf, u16 sendBufSize);
56 #endif
57 
58 /*!
59     @brief 解放します。
60 */
61     void Finalize(void);
62 
63 /*!
64     @brief 接続要求を出すリクエストを発行します。
65            リクエストのキューがいっぱいであるなどの理由で
66            失敗することがあります。
67 */
68     nn::Result Open(void);
69 
70 /*!
71     @brief 接続を閉じるリクエストを発行します。
72            リクエストのキューがいっぱいであるなどの理由で
73            失敗することがあります。
74 */
75     nn::Result Close(void);
76 
77 /*!
78     @brief データをRDTライブラリの送信バッファに書き込み、送信の準備をします。
79     送信バッファがいっぱいの場合は、失敗します。このとき、送信バッファには
80     データは1バイトたりとも書き込まれません。
81     この関数呼び出しで渡したデータが実際に送信されるのは、もう少し後になることに
82     注意して下さい。
83 */
84     nn::Result Send(const void *pBuf, size_t bufSize);
85 
86 /*!
87     @brief 通信処理を進行させます。実際の通信処理は、この関数の内部で実行されます。
88            アプリ側から、毎フレーム程度の間隔で呼び出してもらうことを想定しています。
89 */
90     nn::Result Process(void);
91 
92 /*!
93     @brief 処理の中断をリクエストします。
94 */
95     void Cancel(void);
96 
97 /*!
98     @brief オブジェクトの状態を取得します。
99 */
100     enum SenderState GetStatus(void) const;
101 
102 
103 /*!
104     @brief 配置new演算子です。
105 */
new(size_t size,void * pBuf)106     static void* operator new(size_t size, void *pBuf) throw()
107     {
108         if(size!=sizeof(SenderImpl))
109         {
110             PANIC("Wrong size.\n");
111             return NULL;
112         }
113 
114         if(pBuf==NULL)
115         {
116             PANIC("NULL pointer is detected.\n");
117             return NULL;
118         }
119 
120         ALIGN_ASSERT(pBuf, 8);
121 
122         return pBuf;
123     }
124 
125     // 配置deleteを記述したのだが、delete(m_pImpl, m_workBuf)のように
126     // 呼ぶと、何故かグローバルなdelete(void *p)が呼び出されているようだった。
127     // Webにも上記の説を補強する記述が見つかったので、deleteは定義しないで
128     // 置こうとした。…しかし、それだとRealViewコンパイラにWarningで叱られた。
129     // よって定義だけはしておく。ただし呼ばないこと。
130     // SenderImplは、それを使う人が明示的にデストラクタを呼ぶこと。
131 
132     // C++ Labyringth (http://www.fides.dti.ne.jp/~oka-t/cpplab-placement-new-2.html)
133     // もし operator delete( void *p ) と両方が定義されていた場合は、
134     // operator delete( void *p ) のほうが呼び出される。 これは C++ の
135     // 規格書に述べられていることなのだが、 なんとも不明瞭な仕様だと
136     // 言わざるをえない。昔の仕様との整合性を重んじた結果だろうか。
137 
delete(void * p)138     static void  operator delete (void *p) throw()
139     {
140         PANIC("Do not call this delete!  Please call destructor manually.\n");
141         (void)p;
142     }
143 
144 
145 /*!
146     @brief Senderインスタンスの詳細な内部状態をプリントします。(デバッグ用)
147 */
148     void PrintDebugInfo(void) const;
149 
150 /*!
151     @brief SenderImplクラスの内部構造を知りたくなったときに作った関数です(デバッグ用)
152 */
153     static void PrintProperty(void);
154 
155 /*!
156     @brief CUnitの単体テストです。
157 */
158     static void Test(void);
159 
160 
161 private:
162 /*!
163     @brief コピーコンストラクタは封印します。
164 */
165     SenderImpl           (const SenderImpl&);
166 
167 /*!
168     @brief 代入演算子は封印します。
169 */
170     SenderImpl& operator=(const SenderImpl&);
171 
172 
173     // プライベート関数群。
174     void changeState(void);                // この関数を呼ぶことで、状態遷移が実行される。
175     void setNextState(SenderStateBase *p); // 次の状態をセット。
176 
177     void putSegmentWithResend(const Segment &seg);
178 
179     // segには、受信できたセグメントを与える。
180     // 受信セグメントに対する共通処理がこの関数の中に
181     // まとめられている。
182     void processReceivedSegment(const Segment &seg);
183 
184     // 一連の再送処理を実行する。
185     // セグメントの再送が行われた場合はtrueが返る。
186     // 行われなかった場合はfalse。
187     bool processResending(void);
188 
189     // キャンセル処理を実行。
190     void processCanceling(void);
191 
192     // 送信バッファにデータが溜まっていたら、1つのセグメントに
193     // 収まる量だけ吸い出して、送信します。
194     void sendData(void);
195 
196     // SYN要求を込めたセグメントを作成し、送信します。
197     void sendSynSegment(void);
198 
199     // FIN要求を込めたセグメントを作成し、送信します。
200     // この関数は、送信バッファがカラッポの状況で呼び出す必要があります。
201     void sendFinSegment(void);
202 
203     // 送信バッファはカラッポ?
isSendBufferEmpty(void)204     bool isSendBufferEmpty(void) const { return m_sendBuffer.IsEmpty(); }
205 
206     // Closed状態に入るときなどに呼ばれることを想定。
207     // Stateパターンにおける状態を保持するメンバを除き、
208     // 各種メンバ変数をまっさらな状態に戻す。
209     void clear(void);
210 
211     // ISS(初期シーケンス番号)を取得。
getInitialSequenceNumber(void)212     u32 getInitialSequenceNumber(void) const { return m_iss; }
213 
214     // 到達未確認のオクテットのうち、最も古いシーケンス番号を取得
getUnacknowledgeNumber(void)215     u32 getUnacknowledgeNumber(void) const { return m_una; }
216 
217     // 次に送信することになるオクテットのシーケンス番号
getNextSequenceNumber(void)218     u32 getNextSequenceNumber(void) const { return m_nxt; }
219 
220     // リモートから受信したACKは正当?
221     bool isValidAckNumber(u32 ack) const;
222 
223     // メンバ変数群。
224     SendBuffer    m_sendBuffer;       // 送信バッファ
225     u16           m_remoteWindowSize; // リモート側から通知されたウィンドウサイズの最新情報。
226     bool          m_initialized;
227     u8            m_padding;          // パディング
228     u32           m_iss;              // 初期シーケンス番号
229     u32           m_una;              // 到達未確認のシーケンス番号のうち、最も古いもの
230     u32           m_nxt;              // 次に送信されるべきオクテットのシーケンス番号
231     ResendQueue   m_resendQueue;      // 再送キュー(8バイトアライメントが要求される)
232 
233     // Stateパターンの実践。
234     SenderStateBase *m_pState;
235     SenderStateBase *m_pNextState;
236     friend class SenderStateOpenRequested;
237     friend class SenderStateOpening;
238     friend class SenderStateOpened;
239     friend class SenderStateCloseRequested;
240     friend class SenderStateClosing;
241     friend class SenderStateClosed;
242 
243     // デバッグ用変数
244     u32           m_arrivals;    // セグメント到着回数
245 
246     // SenderImplクラスもResendQueueのアライメントに引きずられるので、
247     // ここでパディングする必要があることもある
248     u8            m_padding2[4];
249 };
250 
251 }}} // namespace nn::rdt::CTR
252 
253 #endif  // end of NN_RDT_SENDERIMPL_H_
254