/*-------------------------------------------------------------------------- Project: HorizonSDK File: rdt_Utility.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-08-06#$ $Rev: 22867 $ $Author: hiratsu_daisuke $ *-------------------------------------------------------------------------*/ #include "stdafx.h" #include "rdt_Utility.h" #include #include #ifdef _WIN32 #include #include #else #include #include #include #endif // end of _WIN32 namespace { #ifdef _WIN32 WSADATA s_wsaData; SOCKET s_sendSock = INVALID_SOCKET; SOCKET s_recvSock = INVALID_SOCKET; u8 s_senderWorkBuf[nn::rdt::CTR::Sender::SENDER_WORKBUF_SIZE]; u8 s_receiverWorkBuf[nn::rdt::CTR::Receiver::RECEIVER_WORKBUF_SIZE]; #endif } // end of anonymous namespace namespace nn { namespace rdt { namespace CTR { #ifdef _WIN32 void SetupNetwork(void) { // winsockのバージョン指定。1.0, 1.1, 2.0の三種類あるらしい。 int result = WSAStartup(MAKEWORD(2, 0), &s_wsaData); assert(result==0); // 成功すれば、ゼロが返される。 } void CleanupNetwork(void) { WSACleanup(); } SOCKET SetupServerSide(u16 port) { using namespace std; SOCKET sock0; // 接続待ち用ソケット struct sockaddr_in addr; // 接続してきたクライアントとペアをなすソケットの情報 struct sockaddr_in client; // 接続してきたクライアントの情報を保持 int len; SOCKET sock; int result = 0; // ソケット作成 sock0 = socket(AF_INET, SOCK_STREAM, 0); // sock0 = socket(AF_UNSPEC, SOCK_STREAM, 0); // わざと失敗する例。 if(sock0==INVALID_SOCKET) { cout << "socket() failed." << "Error: " << WSAGetLastError() << endl; abort(); } // ソケット設定 addr.sin_family = AF_INET; addr.sin_port = htons(port); // バイトオーダーの変換。 Host to Network short。 addr.sin_addr.S_un.S_addr = INADDR_ANY; result = bind(sock0, (struct sockaddr*)&addr, sizeof(addr)); if(result!=0) { cout << "port: " << port << endl; cout << "bind() failed. " << "Error: " << WSAGetLastError() << endl; abort(); } // 待ち受け result = listen(sock0, 5); assert(result==0); // エラー無しなら、listen()はゼロを返す。 // 接続を許可 len = sizeof(client); //// cout << "accept()呼び出し前、lenは" << len << "でした。" << endl; sock = accept(sock0, (struct sockaddr*)&client, &len); if(sock==INVALID_SOCKET) { cout << "accept() failed." << "Error: " << WSAGetLastError() << endl; abort(); } //// cout << "accept()呼び出し後、lenは" << len << "になりました。" << endl; // ソケットをノンブロッキングモードに { u_long val = 1; int ret = ioctlsocket(sock, FIONBIO, &val); if(ret!=0) { printf("error: %d\n", ret); abort(); } } return sock; } void CleanupServerSide(SOCKET sock) { // TCPセッション終了 closesocket(sock); } SOCKET SetupClientSide(u16 port) { struct sockaddr_in server; SOCKET sock; sock = socket(AF_INET, SOCK_STREAM, 0); // 接続先指定用構造体 server.sin_family = AF_INET; server.sin_port = htons(port); // ネットワークバイトオーダーの変換 server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // サーバに接続。エラーが起こらなければ、connect()はゼロを返す。 int ret = connect(sock, (struct sockaddr *)&server, sizeof(server)); assert(ret==0); // ソケットをノンブロッキングモードに { u_long val = 1; int ret = ioctlsocket(sock, FIONBIO, &val); if(ret!=0) { printf("error: %d\n", ret); abort(); } } return sock; } void CleanupClientSide(SOCKET sock) { closesocket(sock); } // 利用可能なポート番号を返す。 // デバッグビルド・リリースビルドでポート番号を使い分ける // (同時実行を狙っているので) u16 GetAvailablePort(void) { const u16 PERIOD = 5000; #ifdef NDEBUG const u16 OFFSET = 50000; #else const u16 OFFSET = 50000 + PERIOD; #endif static u16 s_counter = 0; u16 ret = s_counter + OFFSET; s_counter = (s_counter + 1) % PERIOD; // 自由に使えるポート番号は、49152番 - 65535番 ASSERT((49152<=ret) && (ret <= 65535)); return ret; } // インスタンスの作成・削除。 Sender* CreateSender(u16 port, void *pSendBuf, u16 sendBufSize) { if(s_sendSock==INVALID_SOCKET) { s_sendSock = SetupClientSide(port); if(s_sendSock!=INVALID_SOCKET) { Sender *s = new Sender(); SenderConfig cfg; cfg.pWorkBuf = s_senderWorkBuf; cfg.pSendBuf = pSendBuf; cfg.sendBufSize = sendBufSize; cfg.sock = s_sendSock; nn::Result result = s->Initialize(cfg); if(result.IsFailure()) { PANIC("Senderの初期化に失敗!\n"); } return s; } else { PANIC("ソケットの作成に失敗しました。\n"); return NULL; } } else { PANIC("%sが多重に呼ばれています。\n", __FUNCTION__); return NULL; } } void DestroySender(Sender *s) { ASSERT(s!=NULL); ASSERT(s_sendSock!=INVALID_SOCKET); s->Finalize(); delete s; CleanupClientSide(s_sendSock); s_sendSock = INVALID_SOCKET; } Receiver* CreateReceiver (u16 port, void *pRecvBuf, u16 recvBufSize) { if(s_recvSock==INVALID_SOCKET) { s_recvSock = SetupServerSide(port); if(s_recvSock!=INVALID_SOCKET) { Receiver *r = new Receiver(); ReceiverConfig cfg; cfg.pWorkBuf = s_receiverWorkBuf; cfg.pRecvBuf = pRecvBuf; cfg.recvBufSize = recvBufSize; cfg.sock = s_recvSock; nn::Result result = r->Initialize(cfg); if(result.IsFailure()) { PANIC("Receiverの初期化に失敗!\n"); } return r; } else { PANIC("ソケットの作成に失敗しました。\n"); return NULL; } } else { PANIC("%sが多重に呼ばれています。\n", __FUNCTION__); return NULL; } } void DestroyReceiver(Receiver *r) { ASSERT(r!=NULL); ASSERT(s_recvSock!=INVALID_SOCKET); delete r; CleanupClientSide(s_recvSock); s_recvSock = INVALID_SOCKET; } void SleepCurrentThread(s32 msec) { Sleep(msec); } MSEC_T GetCurrentTimeAsMillisecond(void) { return clock(); } #else // 以下、CTR用。 void SleepCurrentThread(s32 msec) { nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(msec)); } MSEC_T GetCurrentTimeAsMillisecond(void) { return nn::os::Tick::GetSystemCurrent().ToTimeSpan().GetMilliSeconds(); } void PrintResultCode(nn::Result r) { if(r.IsSuccess()) { LOG("Success.\n"); } else { #if 0 LOG("Failure...\n"); LOG(" Level = %d\n", r.GetLevel()); LOG(" Summary = %d\n", r.GetSummary()); LOG(" Module = %d\n", r.GetModule()); LOG(" Description = %d\n", r.GetDescription()); LOG(" (0x%08x)\n", r.GetPrintableBits()); #else LOG("Failure...\n"); nn::dbg::PrintResult(r); #endif } } #endif // この関数を呼び出した時点で、どれだけスタックが食いつぶされているかを得る。 void stackChecker(void) { int dmy; #ifdef NN_SWITCH_DISABLE_DEBUG_PRINT NN_UNUSED_VAR(dmy); #endif LOG("addr: 0x%08x\n", &dmy); LOG("%d bytes used.\n", 0x0fffffff - reinterpret_cast(&dmy)); } }}} // namespace nn::rdt::CTR