ctr_Repair/trunk/ConsoleDataMigration/sources/ConsoleRestore/Shop.cpp
N2614 a96ae0accd nim系デバッグ出力の整理
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@296 385bec56-5757-e545-9c3a-d8741f4650f1
2011-05-31 08:43:54 +00:00

565 lines
17 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: Shop.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.
$Rev$
*---------------------------------------------------------------------------*/
#include <nn/os.h>
#include <nn/Handle.h>
#include <nn/dbg.h>
#include <nn/nim.h>
#include <nn/ac/private/ac.h>
#include <nn/ac/CTR/private/ac_InternalApi.h>
#include <nn/nim/CTR/private/nim_ShopPrivateApi.h>
#include <nn/CTR/CTR_ProgramId.h>
#include <nn/am.h>
#include "Shop.h"
#include "CommonLogger.h"
using namespace ES_NAMESPACE;
using namespace EC_NAMESPACE;
#define NIM_SHOP_RESULT_CHECK(result) \
do { \
if (result.IsFailure()) \
{ \
ECCustomerSupportCode csc; \
nn::nim::Shop::GetCustomerSupportCode(&csc); \
COMMON_LOGGER("CSCode: %d\n", csc); \
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result); \
nn::dbg::PrintResult(result); \
COMMON_LOGGER_DEBUG("Result = %08X\n", result.GetPrintableBits()); \
s_ShopResult = result; \
return; \
} \
} while(0)
namespace
{
nn::Result s_ShopResult = nn::ResultSuccess();
const size_t SHOP_OPERATION_THREAD_STACK_SIZE = 0x1000;
nn::os::Thread s_ShopOperationThread;
nn::os::StackBuffer<SHOP_OPERATION_THREAD_STACK_SIZE> s_ShopOperationThreadStack;
const size_t EC_BUFFER_SIZE = 128 * 1024;
u8 s_EcBufffer[EC_BUFFER_SIZE];
bool s_IsNimShopInitialized = false;
struct ShopThreadParam
{
ConsoleRestore::ShopOperation op;
nn::nim::TitleConfig config;
};
// TitleProgress の ==, != を定義
bool operator==(
nn::nim::TitleProgress& lhs,
nn::nim::TitleProgress& rhs)
{
return (lhs.state == rhs.state &&
lhs.lastResult == rhs.lastResult &&
lhs.downloadedSize == rhs.downloadedSize &&
lhs.totalSize == rhs.totalSize);
}
bool operator!=(
nn::nim::TitleProgress& lhs,
nn::nim::TitleProgress& rhs)
{
return (! (lhs == rhs));
}
// TitleState の文字列を取得
#ifdef NN_BUILD_VERBOSE
const char* GetTitleStateString(nn::nim::TitleState state)
{
switch (state)
{
case nn::nim::TITLE_STATE_NOT_INITIALIZED:
return "NOT_INITIALIZED";
case nn::nim::TITLE_STATE_INITIALIZED:
return "INITIALIZED";
case nn::nim::TITLE_STATE_DOWNLOAD_TMD:
return "DOWNLOAD_TMD";
case nn::nim::TITLE_STATE_PREPARE_SAVE_DATA:
return "PREPARE_SAVE_DATA";
case nn::nim::TITLE_STATE_DOWNLOAD_CONTENTS:
return "DOWNLOAD_CONTENTS";
case nn::nim::TITLE_STATE_WAIT_COMMIT:
return "WAIT_COMMIT";
case nn::nim::TITLE_STATE_COMMITTING:
return "COMMITTING";
case nn::nim::TITLE_STATE_FINISHED:
return "FINISHED";
case nn::nim::TITLE_STATE_VERSION_MISMATCH:
return "VERSION_MISMATCH";
default:
return "UNKNOWN";
}
}
#endif
// 空文字列と NULL ポインタをそれぞれ <empty> と NULL として返す
#ifdef NN_BUILD_VERBOSE
const char* Cstr(const char* p)
{
return p ? (p[0] ? p : "<empty>") : "NULL";
}
#endif
// ECTicketVersions を出力
void PrintECTicketVersions(const ECTicketVersions& ticketVersions)
{
if (ticketVersions.nTicketVersions == 0)
{
COMMON_LOGGER_DEBUG("No TicketVersions\n");
return;
}
COMMON_LOGGER_DEBUG("----- ECTicketVersions -----\n");
for (u32 i = 0; i < ticketVersions.nTicketVersions; i++)
{
#ifdef NN_BUILD_VERBOSE
ECTicketVersion version = ticketVersions.ticketVersions[i];
#endif
COMMON_LOGGER_DEBUG("%03d: 0x%016llx v%d\n", i, version.ticketId, version.version);
}
COMMON_LOGGER_DEBUG("---------------------------\n");
}
// ECAccountInfo の情報を出力
void PrintECAccountInfo(const ECAccountInfo& accountInfo)
{
COMMON_LOGGER_DEBUG("========== ECAccountInfo ==========\n");
COMMON_LOGGER_DEBUG("accountId\n %s\n", Cstr(accountInfo.accountId));
COMMON_LOGGER_DEBUG("accountStatus\n %s\n", Cstr(accountInfo.accountStatus));
if (accountInfo.accountBalance == NULL)
{
COMMON_LOGGER_DEBUG("accountBalance\n NULL\n");
}
else
{
COMMON_LOGGER_DEBUG("accountBalance->amount\n %s\n",
Cstr(accountInfo.accountBalance->amount));
COMMON_LOGGER_DEBUG("accountBalance->currency\n %s\n",
Cstr(accountInfo.accountBalance->currency));
}
if (accountInfo.agreedEULAVersion == NULL)
{
COMMON_LOGGER_DEBUG("agreedEULAVersion\n NULL\n");
}
else
{
COMMON_LOGGER_DEBUG("agreedEULAVersion\n %lld\n",
*accountInfo.agreedEULAVersion);
}
if (accountInfo.latestEULAVersion == NULL)
{
COMMON_LOGGER_DEBUG("latestEULAVersion\n NULL\n");
}
else
{
COMMON_LOGGER_DEBUG("latestEULAVersion\n %lld\n",
*accountInfo.latestEULAVersion);
}
COMMON_LOGGER_DEBUG("country\n %s\n", Cstr(accountInfo.country));
COMMON_LOGGER_DEBUG("extAccountId\n %s\n", Cstr(accountInfo.extAccountId));
COMMON_LOGGER_DEBUG("deviceToken\n %s\n", Cstr(accountInfo.deviceToken));
COMMON_LOGGER_DEBUG("weakToken\n %s\n", Cstr(accountInfo.weakToken));
COMMON_LOGGER_DEBUG("isStandbyMode\n %d\n", accountInfo.isStandbyMode);
if (accountInfo.owned == NULL)
{
COMMON_LOGGER_DEBUG("owned\n NULL\n");
}
else
{
PrintECTicketVersions(*(accountInfo.owned));
}
}
nn::Result PrintNetworkSetting()
{
nn::Result result;
nn::ac::NetworkSetting networkSetting;
result = nn::ac::LoadNetworkSetting(0, networkSetting);
COMMON_LOGGER("SSID: %s\n", networkSetting.wireless.essidSecurity.ssid);
COMMON_LOGGER("DNS : %d.%d.%d.%d\n",
networkSetting.ip.dns[0][0], networkSetting.ip.dns[0][1],
networkSetting.ip.dns[0][2], networkSetting.ip.dns[0][3]);
return result;
}
nn::Result ConnectNetwork()
{
nn::Result result;
nn::ac::Config config;
result = nn::ac::CreateDefaultConfig(&config);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
result = nn::ac::ConnectWithoutEula(config);
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
COMMON_LOGGER_DEBUG("Success nn::ac::ConnectWithoutEula\n");
result = PrintNetworkSetting();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result InitializeInternal()
{
nn::Result result;
result = nn::ac::InitializeInternal();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
result = ConnectNetwork();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result FinalizeInternal()
{
nn::Result result = nn::ResultSuccess();
nn::ac::CloseAll();
result = nn::ac::FinalizeInternal();
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
}
namespace ConsoleRestore{
nn::Result ShopOperationConnect();
nn::Result ShopOperationFinalize();
nn::Result CheckStandbyMode(s32 isStandbyMode)
{
if(isStandbyMode)
{
COMMON_LOGGER("Shop is Standby Mode\n");
return nn::MakePermanentResult(nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_NOT_AUTHORIZED);
}
else
{
return nn::ResultSuccess();
}
}
nn::Result ShopOperationConnect(ECAccountInfo** pAccountInfo)
{
nn::Result result = nn::ResultSuccess();
/* -------------------------------------------------------------------
Connect
-------------------------------------------------------------------- */
COMMON_LOGGER_DEBUG("nim::Shop::Connect\n");
result = nn::nim::Shop::Connect(pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE);
NN_UTIL_RETURN_IF_FAILED(result);
result = CheckStandbyMode((*pAccountInfo)->isStandbyMode);
NN_UTIL_RETURN_IF_FAILED(result);
PrintECAccountInfo(**pAccountInfo);
COMMON_LOGGER_DEBUG("\n");
return result;
}
nn::Result ShopOperationInitialize()
{
nn::Result result = nn::ResultSuccess();
/* -------------------------------------------------------------------
Initialize
-------------------------------------------------------------------- */
if (!s_IsNimShopInitialized)
{
COMMON_LOGGER_DEBUG("nim::InitializeForShop\n");
result = nn::nim::InitializeForShop();
NN_UTIL_RETURN_IF_FAILED(result);
s_IsNimShopInitialized = true;
}
/* -------------------------------------------------------------------
SetParameter
-------------------------------------------------------------------- */
COMMON_LOGGER_DEBUG("nim::Shop::SetApplication Id\n");
nn::nim::Shop::SetApplicationId();
NN_UTIL_RETURN_IF_FAILED(result);
COMMON_LOGGER_DEBUG("nim::Shop::SetTIN\n");
result = nn::nim::Shop::SetTin(CONSOLE_RESTORE_TIN);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result ShopOperationConnect()
{
nn::Result result;
result = ShopOperationInitialize();
NN_UTIL_RETURN_IF_FAILED(result);
/* -------------------------------------------------------------------
Connect
-------------------------------------------------------------------- */
ECAccountInfo* pAccountInfo;
result = ShopOperationConnect(&pAccountInfo);
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
nn::Result ShopOperationFinalize()
{
nn::Result result = nn::ResultSuccess();
/* -------------------------------------------------------------------
Finalize
-------------------------------------------------------------------- */
COMMON_LOGGER_DEBUG("nim::FinalizeForShop\n");
result = nn::nim::FinalizeForShop();
NN_UTIL_RETURN_IF_FAILED(result);
s_IsNimShopInitialized = false;
COMMON_LOGGER_DEBUG("util::ac::Finalize\n");
result = FinalizeInternal();
NN_UTIL_RETURN_IF_FAILED(result);
return result;
}
namespace
{
void ShopOperationUnregisterCore(bool force)
{
nn::Result result;
result = ShopOperationInitialize();
NIM_SHOP_RESULT_CHECK(result);
ECAccountInfo* pAccountInfo;
result = ShopOperationConnect(&pAccountInfo);
NIM_SHOP_RESULT_CHECK(result);
if(force)
{
if (pAccountInfo->accountStatus && (pAccountInfo->accountStatus[0] == 'R' ||
pAccountInfo->accountStatus[0] == 'T'))
{
COMMON_LOGGER_DEBUG("nim::Shop::Unregister\n");
result = nn::nim::Shop::Unregister();
NIM_SHOP_RESULT_CHECK(result);
}
}
else
{
if (pAccountInfo->accountStatus && (pAccountInfo->accountStatus[0] == 'R'))
{
COMMON_LOGGER_DEBUG("nim::Shop::Unregister\n");
result = nn::nim::Shop::Unregister();
NIM_SHOP_RESULT_CHECK(result);
}
else
{
COMMON_LOGGER_DEBUG("Not registered.\n");
}
}
}
// メイン関数
void ShopOperationSingleThreadFunc(ShopThreadParam param)
{
nn::Result result;
s_ShopResult = nn::ResultSuccess();
COMMON_LOGGER_DEBUG("util::ac::Initialize\n");
result = InitializeInternal();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
NIM_SHOP_RESULT_CHECK(result);
switch(param.op)
{
case SHOP_OPERATION_CONNECT:
{
result = ShopOperationConnect();
NIM_SHOP_RESULT_CHECK(result);
}
break;
case SHOP_OPERATION_GET_IVS:
{
result = ShopOperationInitialize();
NIM_SHOP_RESULT_CHECK(result);
// IVSを取得する
result = nn::nim::Shop::ImportIvsFromInfrastructure();
NIM_SHOP_RESULT_CHECK(result);
}
break;
case SHOP_OPERATION_UNREGISTER:
{
ShopOperationUnregisterCore(false);
}
break;
case SHOP_OPERATION_FORCE_UNREGISTER:
{
ShopOperationUnregisterCore(true);
}
break;
case SHOP_OPERATION_CONNECT_WITHOUT_CLOSE:
{
result = ShopOperationConnect();
NIM_SHOP_RESULT_CHECK(result);
return;
}
{
case SHOP_OPERATION_DOWNLOAD_TITLE:
COMMON_LOGGER_DEBUG("Try Download %016llx\n", param.config.titleId);
result = nn::nim::Shop::StartDownload(param.config);
if (result == nn::nim::ResultBusy() || result == nn::nim::ResultAlreadyDone())
{
COMMON_LOGGER("Download Content -> Nim is busy\n");
}
else if (result == nn::nim::ResultInvalidTitle())
{
COMMON_LOGGER("Download Content -> Invalid Title\n");
}
else if (result.IsFailure())
{
COMMON_LOGGER("Download Content -> Failure %x\n", result.GetPrintableBits());
}
/* -------------------------------------------------------------------
GetProgress
-------------------------------------------------------------------- */
COMMON_LOGGER_DEBUG("nim::Shop::GetProgress()\n");
nn::nim::TitleProgress before;
nn::nim::TitleProgress latest;
while (true)
{
result = nn::nim::Shop::GetProgress(&latest);
// 既にインポート済み
if (result == nn::am::ResultAlreadyExists())
{
break;
}
NIM_SHOP_RESULT_CHECK(result);
// Print progress
if (latest != before)
{
COMMON_LOGGER_DEBUG("%8lld / %8lld (%d:%s)\n",
latest.downloadedSize,
latest.totalSize,
latest.state.Get(),
GetTitleStateString(latest.state));
if (latest.state == nn::nim::TITLE_STATE_FINISHED)
{
COMMON_LOGGER_DEBUG("Finished Download\n");
break;
}
before = latest;
}
// あまりにも頻繁に GetProgress を呼ぶと、ダウンロード処理の速度に
// 影響が出てしまいます。少なくとも数フレーム以上の間隔をあけて
// GetProgress することを推奨します。
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
}
}
break;
}
result = ShopOperationFinalize();
NIM_SHOP_RESULT_CHECK(result);
}
}
void StartShopOperationSingle(ShopOperation op, nn::nim::TitleConfig config)
{
COMMON_LOGGER_DEBUG("Start ShopOperationSingle, %s\n", SHOP_OPERATION_STR[op]);
ShopThreadParam param;
param.op = op;
param.config = config;
s_ShopOperationThread.Start(ShopOperationSingleThreadFunc, param, s_ShopOperationThreadStack);
}
void StartShopOperationSingle(ShopOperation op)
{
ShopThreadParam param;
param.op = op;
COMMON_LOGGER_DEBUG("Start ShopOperationSingle, %s\n", SHOP_OPERATION_STR[op]);
s_ShopOperationThread.Start(ShopOperationSingleThreadFunc, param, s_ShopOperationThreadStack);
}
void FinalizeShopOperationSingle()
{
COMMON_LOGGER_DEBUG("Finalize ShopOperationSingle\n");
s_ShopOperationThread.Join();
s_ShopOperationThread.Finalize();
}
bool IsShopOperationSingleFinished()
{
return s_ShopOperationThread.IsValid() && !s_ShopOperationThread.IsAlive();
}
nn::Result GetShopOperationSingleResult()
{
return s_ShopResult;
}
}