1 /*--------------------------------------------------------------------------
2   Project:  HorizonSDK
3   File:     rdt_Utility.cpp
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-10-19#$
14   $Rev: 28318 $
15   $Author: hiratsu_daisuke $
16  *-------------------------------------------------------------------------*/
17 
18 #include "stdafx.h"
19 
20 #include "rdt_Utility.h"
21 
22 #include <nn/rdt/CTR/rdt_Sender.h>
23 #include <nn/rdt/CTR/rdt_Receiver.h>
24 
25 #ifdef _WIN32
26 #include <iostream>
27 #include <assert.h>
28 #else
29 #include <nn/os.h>
30 #include <nn/fnd.h>
31 #include <nn/dbg.h>
32 #endif  // end of _WIN32
33 
34 namespace
35 {
36 #ifdef _WIN32
37     WSADATA s_wsaData;
38     SOCKET  s_sendSock = INVALID_SOCKET;
39     SOCKET  s_recvSock = INVALID_SOCKET;
40     u8      s_senderWorkBuf[nn::rdt::CTR::Sender::SENDER_WORKBUF_SIZE];
41     u8      s_receiverWorkBuf[nn::rdt::CTR::Receiver::RECEIVER_WORKBUF_SIZE];
42 #endif
43 }  // end of anonymous namespace
44 
45 namespace nn { namespace rdt { namespace CTR {
46 
47 
48 #ifdef _WIN32
SetupNetwork(void)49 void SetupNetwork(void)
50 {
51     // winsockのバージョン指定。1.0, 1.1, 2.0の三種類あるらしい。
52     int result = WSAStartup(MAKEWORD(2, 0), &s_wsaData);
53     assert(result==0);  // 成功すれば、ゼロが返される。
54 }
55 
56 
CleanupNetwork(void)57 void CleanupNetwork(void)
58 {
59     WSACleanup();
60 }
61 
62 
SetupServerSide(u16 port)63 SOCKET SetupServerSide(u16 port)
64 {
65     using namespace std;
66 
67     SOCKET sock0;              // 接続待ち用ソケット
68     struct sockaddr_in addr;   // 接続してきたクライアントとペアをなすソケットの情報
69     struct sockaddr_in client; // 接続してきたクライアントの情報を保持
70     int len;
71     SOCKET sock;
72     int result = 0;
73 
74     // ソケット作成
75     sock0 = socket(AF_INET, SOCK_STREAM, 0);
76     // sock0 = socket(AF_UNSPEC, SOCK_STREAM, 0);  // わざと失敗する例。
77     if(sock0==INVALID_SOCKET)
78     {
79         cout << "socket() failed." << "Error: " << WSAGetLastError() << endl;
80         abort();
81     }
82 
83     // ソケット設定
84     addr.sin_family = AF_INET;
85     addr.sin_port = htons(port);  // バイトオーダーの変換。 Host to Network short。
86     addr.sin_addr.S_un.S_addr = INADDR_ANY;
87     result = bind(sock0, (struct sockaddr*)&addr, sizeof(addr));
88     if(result!=0)
89     {
90         cout << "port: " << port << endl;
91         cout << "bind() failed. " << "Error: " << WSAGetLastError() << endl;
92         abort();
93     }
94 
95     // 待ち受け
96     result = listen(sock0, 5);
97     assert(result==0);  // エラー無しなら、listen()はゼロを返す。
98 
99 
100     // 接続を許可
101     len = sizeof(client);
102 ////    cout << "accept()呼び出し前、lenは" << len << "でした。" << endl;
103     sock = accept(sock0, (struct sockaddr*)&client, &len);
104     if(sock==INVALID_SOCKET)
105     {
106         cout << "accept() failed." << "Error: " << WSAGetLastError() << endl;
107         abort();
108     }
109 ////    cout << "accept()呼び出し後、lenは" << len << "になりました。" << endl;
110 
111     // ソケットをノンブロッキングモードに
112     {
113         u_long val = 1;
114         int ret = ioctlsocket(sock, FIONBIO, &val);
115         if(ret!=0)
116         {
117             printf("error: %d\n", ret);
118             abort();
119         }
120     }
121 
122     return sock;
123 }
124 
125 
CleanupServerSide(SOCKET sock)126 void CleanupServerSide(SOCKET sock)
127 {
128     // TCPセッション終了
129     closesocket(sock);
130 }
131 
132 
SetupClientSide(u16 port)133 SOCKET SetupClientSide(u16 port)
134 {
135     struct sockaddr_in server;
136     SOCKET sock;
137 
138     sock = socket(AF_INET, SOCK_STREAM, 0);
139 
140     // 接続先指定用構造体
141     server.sin_family = AF_INET;
142     server.sin_port   = htons(port);  // ネットワークバイトオーダーの変換
143     server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
144 
145     // サーバに接続。エラーが起こらなければ、connect()はゼロを返す。
146     int ret = connect(sock, (struct sockaddr *)&server, sizeof(server));
147     assert(ret==0);
148 
149     // ソケットをノンブロッキングモードに
150     {
151         u_long val = 1;
152         int ret = ioctlsocket(sock, FIONBIO, &val);
153         if(ret!=0)
154         {
155             printf("error: %d\n", ret);
156             abort();
157         }
158     }
159 
160     return sock;
161 }
162 
163 
CleanupClientSide(SOCKET sock)164 void CleanupClientSide(SOCKET sock)
165 {
166     closesocket(sock);
167 }
168 
169 
170 // 利用可能なポート番号を返す。
171 // デバッグビルド・リリースビルドでポート番号を使い分ける
172 // (同時実行を狙っているので)
GetAvailablePort(void)173 u16 GetAvailablePort(void)
174 {
175     const u16 PERIOD = 5000;
176 #ifdef NDEBUG
177     const u16 OFFSET = 50000;
178 #else
179     const u16 OFFSET = 50000 + PERIOD;
180 #endif
181 
182     static u16 s_counter = 0;
183 
184     u16 ret = s_counter + OFFSET;
185     s_counter = (s_counter + 1) % PERIOD;
186 
187     // 自由に使えるポート番号は、49152番 - 65535番
188     ASSERT((49152<=ret) && (ret <= 65535));
189     return ret;
190 }
191 
192 
193 // インスタンスの作成・削除。
CreateSender(u16 port,void * pSendBuf,u16 sendBufSize)194 Sender* CreateSender(u16 port, void *pSendBuf, u16 sendBufSize)
195 {
196     if(s_sendSock==INVALID_SOCKET)
197     {
198         s_sendSock = SetupClientSide(port);
199         if(s_sendSock!=INVALID_SOCKET)
200         {
201             Sender *s = new Sender();
202             SenderConfig cfg;
203             cfg.pWorkBuf    = s_senderWorkBuf;
204             cfg.pSendBuf    = pSendBuf;
205             cfg.sendBufSize = sendBufSize;
206             cfg.sock        = s_sendSock;
207             nn::Result result = s->Initialize(cfg);
208             if(result.IsFailure())
209             {
210                 PANIC("Senderの初期化に失敗!\n");
211             }
212             return s;
213         }
214         else
215         {
216             PANIC("ソケットの作成に失敗しました。\n");
217             return NULL;
218         }
219     }
220     else
221     {
222         PANIC("%sが多重に呼ばれています。\n", __FUNCTION__);
223         return NULL;
224     }
225 }
226 
227 
DestroySender(Sender * s)228 void DestroySender(Sender *s)
229 {
230     ASSERT(s!=NULL);
231     ASSERT(s_sendSock!=INVALID_SOCKET);
232 
233     s->Finalize();
234     delete s;
235     CleanupClientSide(s_sendSock);
236     s_sendSock = INVALID_SOCKET;
237 }
238 
239 
CreateReceiver(u16 port,void * pRecvBuf,u16 recvBufSize)240 Receiver* CreateReceiver (u16 port, void *pRecvBuf, u16 recvBufSize)
241 {
242     if(s_recvSock==INVALID_SOCKET)
243     {
244         s_recvSock = SetupServerSide(port);
245         if(s_recvSock!=INVALID_SOCKET)
246         {
247             Receiver *r = new Receiver();
248             ReceiverConfig cfg;
249             cfg.pWorkBuf    = s_receiverWorkBuf;
250             cfg.pRecvBuf    = pRecvBuf;
251             cfg.recvBufSize = recvBufSize;
252             cfg.sock        = s_recvSock;
253             nn::Result result = r->Initialize(cfg);
254             if(result.IsFailure())
255             {
256                 PANIC("Receiverの初期化に失敗!\n");
257             }
258             return r;
259         }
260         else
261         {
262             PANIC("ソケットの作成に失敗しました。\n");
263             return NULL;
264         }
265     }
266     else
267     {
268         PANIC("%sが多重に呼ばれています。\n", __FUNCTION__);
269         return NULL;
270     }
271 }
272 
273 
DestroyReceiver(Receiver * r)274 void DestroyReceiver(Receiver *r)
275 {
276     ASSERT(r!=NULL);
277     ASSERT(s_recvSock!=INVALID_SOCKET);
278 
279     delete r;
280     CleanupClientSide(s_recvSock);
281     s_recvSock = INVALID_SOCKET;
282 }
283 
284 
SleepCurrentThread(s32 msec)285 void SleepCurrentThread(s32 msec)
286 {
287     Sleep(msec);
288 }
289 
290 
GetCurrentTimeAsMillisecond(void)291 MSEC_T GetCurrentTimeAsMillisecond(void)
292 {
293     return clock();
294 }
295 
296 
297 #else
298 // 以下、CTR用。
299 
300 
301 void SleepCurrentThread(s32 msec)
302 {
303     nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(msec));
304 }
305 
306 
307 MSEC_T GetCurrentTimeAsMillisecond(void)
308 {
309     return nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds();
310 }
311 
312 
313 void PrintResultCode(nn::Result r)
314 {
315     if(GetLogLevel()==LOG_LEVEL_ALL)
316     {
317         if(r.IsSuccess())
318         {
319             LOG("Success.\n");
320         }
321         else
322         {
323             LOG("Failure...\n");
324             nn::dbg::PrintResult(r);
325         }
326     }
327 }
328 
329 
330 #endif
331 
332 // この関数を呼び出した時点で、どれだけスタックが食いつぶされているかを得る。
stackChecker(void)333 void stackChecker(void)
334 {
335     int dmy;
336 #ifdef NN_SWITCH_DISABLE_DEBUG_PRINT
337     NN_UNUSED_VAR(dmy);
338 #endif
339     LOG("addr: 0x%08x\n", &dmy);
340     LOG("%d bytes used.\n", 0x0fffffff - reinterpret_cast<u32>(&dmy));
341 }
342 
343 
344 
345 }}} // namespace nn::rdt::CTR
346