NP code review
Some checks are pending
Generate Translation Template / Generate Translation Template (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.9, ubuntu-24.04-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.9, ubuntu-24.04) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Waiting to run
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Waiting to run
Build RPCS3 / RPCS3 Windows (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Waiting to run
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Waiting to run
Build RPCS3 / RPCS3 FreeBSD (push) Waiting to run

sceNpTrophy fixes

- sceNpTrophyGetTrophyUnlockState: signed 1 was potentially shifted by 31(UB)
- sceNpTrophyUnlockTrophy: used a reader_lock and was missing check for read only context

cellGame fixes

- cellHddGameCheck: missing log parameters
- cellGameDataCheckCreate2: missing log parameter
- cellGameThemeInstall: condition inverted checking for extension + added tolower just in case
- cellGameThemeInstallFromBuffer: OOB access, buf is always filled from the start and then used as a parameter to the CB

sceNp fixes

- sceNpManagerGetTicket: Made accurate from RE
- sceNpDrmGetTimelimit: Fix msec calculation

sceNp2 fixes

-sceNpMatching2ContextStartAsync: avoid capturing ctx
-sceNpMatching2ContextStop: Minor error value swap

rpcn_client fixes

-add_friend: missing log parameter
-handle_friend_notification: misc validation issue

np_handler fixes
-ticket: Missing move in move constructor
-ticket::parse: Misc validation fix
-get_player_history_entry: potential UB fix

np_requests fixes

-Wrong CB event_type set for get_room_member_data_external_list!
-reply_tus_get_data was not copying status data!
-Order of error check in reply_get_room_member_data_external_list was wrong
-Improved logging

np_requests_gui:

-Added missing guards for gui_notifications

upnp_handler fixes

-Highest density of bugs per line of code in the west, let's pretend I never wrote this

signaling_handler fixes

-Swapped to multimap to avoid collisions on timestamps

Misc fixes
This commit is contained in:
RipleyTom 2026-02-28 18:55:31 +01:00 committed by Elad
parent 198c2e9eb8
commit 5ca19eabd5
16 changed files with 111 additions and 89 deletions

View file

@ -329,7 +329,7 @@ bool patch_engine::load(patch_map& patches_map, const std::string& path, std::st
is_valid = false;
continue;
}
else if (serial.size() != 9 || !std::all_of(serial.begin(), serial.end(), [](char c) { return std::isalnum(c); }))
else if (serial.size() != 9 || !std::all_of(serial.begin(), serial.end(), [](char c) { return std::isalnum(static_cast<unsigned char>(c)); }))
{
append_log_message(log_messages, fmt::format("Error: Serial '%s' invalid (patch: %s, key: %s, location: %s, file: %s)", serial, description, main_key, get_yaml_node_location(serial_node), path), &patch_log.error);
is_valid = false;

View file

@ -492,8 +492,8 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i)));
}
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
}
// TODO ?
@ -580,7 +580,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
break;
default:
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg);
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->result, result->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg);
break;
}
@ -1199,7 +1199,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
break;
default:
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg);
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->result, cbResult->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg);
break;
}
@ -1747,7 +1747,7 @@ error_code cellGameThemeInstall(vm::cptr<char> usrdirPath, vm::cptr<char> fileNa
{
u32 magic{};
if (src_path.ends_with(".p3t") || !theme.read(magic) || magic != "P3TF"_u32)
if (!fmt::to_lower(src_path).ends_with(".p3t") || !theme.read(magic) || magic != "P3TF"_u32)
{
return CELL_GAME_ERROR_INVALID_THEME_FILE;
}
@ -1819,7 +1819,7 @@ error_code cellGameThemeInstallFromBuffer(ppu_thread& ppu, u32 fileSize, u32 buf
const u32 read_size = std::min(bufSize, fileSize - file_offset);
cellGame.notice("cellGameThemeInstallFromBuffer: writing %d bytes at pos %d", read_size, file_offset);
if (theme.write(reinterpret_cast<u8*>(buf.get_ptr()) + file_offset, read_size) != read_size)
if (theme.write(reinterpret_cast<u8*>(buf.get_ptr()), read_size) != read_size)
{
cellGame.error("cellGameThemeInstallFromBuffer: failed to write to destination file '%s' (error=%s)", dst_path, fs::g_tls_error);

View file

@ -871,7 +871,7 @@ error_code sceNpDrmGetTimelimit(vm::cptr<char> path, vm::ptr<u64> time_remain)
}
// Convert time to milliseconds
s64 msec = *sec * 1000ll + *nsec / 1000ll;
s64 msec = *sec * 1000ll + *nsec / 1'000'000ll;
// Return the remaining time in microseconds
if (npd.activate_time != 0 && msec < npd.activate_time)
@ -4242,19 +4242,16 @@ error_code sceNpManagerGetTicket(vm::ptr<void> buffer, vm::ptr<u32> bufferSize)
}
const auto& ticket = nph.get_ticket();
*bufferSize = static_cast<u32>(ticket.size());
if (!buffer)
{
*bufferSize = static_cast<u32>(ticket.size());
return CELL_OK;
}
if (*bufferSize < ticket.size())
{
return SCE_NP_ERROR_INVALID_ARGUMENT;
}
memcpy(buffer.get_ptr(), ticket.data(), ticket.size());
const u32 size_read = std::min(::size32(ticket), static_cast<u32>(*bufferSize));
std::memcpy(buffer.get_ptr(), ticket.data(), size_read);
*bufferSize = size_read;
return CELL_OK;
}
@ -5676,7 +5673,7 @@ error_code scenp_score_record_score(s32 transId, SceNpScoreBoardId boardId, SceN
else
{
data = &gameInfo->nativeData[0];
data_size = 64;
data_size = sizeof(gameInfo->nativeData);
}
nph.record_score(trans_ctx, boardId, score, scoreComment, data, data_size, tmpRank, async);

View file

@ -1135,7 +1135,7 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
{
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
{
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
return 0;
});
}
@ -1760,7 +1760,7 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
const auto ctx = get_match2_context(ctxId);
if (!ctx)
return SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID;
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND;
if (!ctx->started.compare_and_swap_test(1, 0))
return SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED;

View file

@ -1026,14 +1026,14 @@ error_code sceNpTrophyUnlockTrophy(ppu_thread& ppu, u32 context, u32 handle, s32
auto& trophy_manager = g_fxo->get<sce_np_trophy_manager>();
reader_lock lock(trophy_manager.mtx);
std::scoped_lock lock(trophy_manager.mtx);
if (!trophy_manager.is_initialized)
{
return SCE_NP_TROPHY_ERROR_NOT_INITIALIZED;
}
const auto [ctxt, error] = trophy_manager.get_context_ex(context, handle);
const auto [ctxt, error] = trophy_manager.get_context_ex(context, handle, true);
if (error)
{
@ -1184,9 +1184,9 @@ error_code sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, vm::ptr<SceN
for (u32 id = 0; id < count_; id++)
{
if (tropusr->GetTrophyUnlockState(id))
flags->flag_bits[id / 32] |= 1 << (id % 32);
flags->flag_bits[id / 32] |= 1u << (id % 32);
else
flags->flag_bits[id / 32] &= ~(1 << (id % 32));
flags->flag_bits[id / 32] &= ~(1u << (id % 32));
}
return CELL_OK;

View file

@ -111,7 +111,7 @@ namespace np
}
ticket::ticket(std::vector<u8>&& raw_data)
: raw_data(raw_data)
: raw_data(std::move(raw_data))
{
parse();
}
@ -387,7 +387,7 @@ namespace np
return;
}
if (nodes[0].id != 0x3000 && nodes[1].id != 0x3002)
if (nodes[0].id != 0x3000 || nodes[1].id != 0x3002)
{
ticket_log.error("The 2 blobs ids are incorrect");
return;
@ -1467,14 +1467,13 @@ namespace np
if (all_history)
{
if (index >= players_history.size())
return false;
auto it = players_history.begin();
std::advance(it, index);
if (it != players_history.end())
{
string_to_npid(it->first, *npid);
return true;
}
string_to_npid(it->first, *npid);
return true;
}
else
{

View file

@ -20,7 +20,7 @@ namespace np
return std::string(ip_str);
}
std::string ether_to_string(std::array<u8, 6>& ether)
std::string ether_to_string(const std::array<u8, 6>& ether)
{
return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
}
@ -110,7 +110,7 @@ namespace np
bool is_valid_npid(const SceNpId& npid)
{
if (!std::all_of(npid.handle.data, npid.handle.data + 16, [](char c) { return std::isalnum(c) || c == '-' || c == '_' || c == 0; } )
if (!std::all_of(npid.handle.data, npid.handle.data + 16, [](char c) { return std::isalnum(static_cast<unsigned char>(c)) || c == '-' || c == '_' || c == 0; } )
|| npid.handle.data[16] != 0
|| !std::all_of(npid.handle.dummy, npid.handle.dummy + 3, [](char val) { return val == 0; }) )
{

View file

@ -7,7 +7,7 @@
namespace np
{
std::string ip_to_string(u32 addr);
std::string ether_to_string(std::array<u8, 6>& ether);
std::string ether_to_string(const std::array<u8, 6>& ether);
bool validate_communication_id(const SceNpCommunicationId& com_id);
std::string communication_id_to_string(const SceNpCommunicationId& communicationId);
std::optional<SceNpCommunicationId> string_to_communication_id(std::string_view str);

View file

@ -381,7 +381,10 @@ namespace np
auto ctx = get_matching_context(ctx_id);
if (!ctx)
{
np_memory.free(edata.addr());
return;
}
gui_cache.add_room(room_info->room_status.id);

View file

@ -191,7 +191,7 @@ namespace np
case rpcn::ErrorType::RoomGroupMaxSlotMismatch: error_code = SCE_NP_MATCHING2_SERVER_ERROR_MAX_OVER_SLOT_GROUP; break;
case rpcn::ErrorType::RoomPasswordMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_PASSWORD; break;
case rpcn::ErrorType::RoomGroupNoJoinLabel: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_JOIN_GROUP_LABEL; break;
default: fmt::throw_exception("Unexpected error in reply to CreateRoom: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to CreateRoom: %s", error);
}
if (error_code != CELL_OK)
@ -262,7 +262,7 @@ namespace np
case rpcn::ErrorType::RoomPasswordMismatch: error_code = SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH; break;
case rpcn::ErrorType::RoomGroupFull: error_code = SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL; break;
case rpcn::ErrorType::RoomGroupJoinLabelNotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP; break;
default: fmt::throw_exception("Unexpected error in reply to JoinRoom: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to JoinRoom: %s", error);
}
if (error_code != 0)
@ -348,7 +348,7 @@ namespace np
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break; // Unsure if this should return another error(missing user in room has no appropriate error code)
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
default: fmt::throw_exception("Unexpected error in reply to LeaveRoom: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to LeaveRoom: %s", error);
}
if (error_code != CELL_OK)
@ -447,7 +447,7 @@ namespace np
u32 np_handler::get_room_member_data_external_list(SceNpMatching2ContextId ctx_id, vm::cptr<SceNpMatching2RequestOptParam> optParam, const SceNpMatching2GetRoomMemberDataExternalListRequest* req)
{
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList, true);
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataExternalList, true);
if (!get_rpcn()->get_room_member_data_external_list(req_id, get_match2_context(ctx_id)->communicationId, req->roomId))
{
@ -465,13 +465,18 @@ namespace np
if (!cb_info_opt)
return;
ensure(error == rpcn::ErrorType::NoError, "Unexpected error in GetRoomMemberDataExternalList reply");
if (error == rpcn::ErrorType::RoomMissing)
switch (error)
{
case rpcn::ErrorType::NoError:
break;
case rpcn::ErrorType::RoomMissing:
{
cb_info_opt->queue_callback(req_id, 0, SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM, 0);
return;
}
default:
fmt::throw_exception("Unexpected error in GetRoomMemberDataExternalList reply: %s", error);
}
const auto resp = reply.get_protobuf<np2_structs::GetRoomMemberDataExternalListResponse>();
ensure(!reply.is_error(), "Malformed reply to GetRoomMemberDataExternalList command");
@ -518,7 +523,7 @@ namespace np
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN; break;
default: fmt::throw_exception("Unexpected error in reply to SetRoomDataExternal: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to SetRoomDataExternal: %s", error);
}
cb_info_opt->queue_callback(req_id, 0, error_code, 0);
@ -550,7 +555,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %s", error);
}
if (error_code != CELL_OK)
@ -606,7 +611,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
default: fmt::throw_exception("Unexpected error in reply to GetRoomDataInternal: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to SetRoomDataInternal: %s", error);
}
cb_info_opt->queue_callback(req_id, 0, error_code, 0);
@ -640,7 +645,7 @@ namespace np
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER; break;
default: fmt::throw_exception("Unexpected error in reply to GetRoomMemberDataInternal: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to GetRoomMemberDataInternal: %s", error);
}
if (error_code != CELL_OK)
@ -694,7 +699,7 @@ namespace np
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
case rpcn::ErrorType::NotFound: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER; break;
case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN; break;
default: fmt::throw_exception("Unexpected error in reply to SetRoomMemberDataInternal: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to SetRoomMemberDataInternal: %s", error);
}
cb_info_opt->queue_callback(req_id, 0, error_code, 0);
@ -723,7 +728,7 @@ namespace np
switch (error)
{
case rpcn::ErrorType::NoError: break;
default: fmt::throw_exception("Unexpected error in reply to SetUserInfo: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to SetUserInfo: %s", error);
}
cb_info_opt->queue_callback(req_id, 0, 0, 0);
@ -755,7 +760,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
default: fmt::throw_exception("Unexpected error in reply to PingRoomOwner: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to PingRoomOwner: %s", error);
}
if (error_code != CELL_OK)
@ -803,7 +808,7 @@ namespace np
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::RoomMissing: error_code = SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM; break;
case rpcn::ErrorType::Unauthorized: error_code = SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN; break;
default: fmt::throw_exception("Unexpected error in reply to SendRoomMessage: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to SendRoomMessage: %s", error);
}
cb_info_opt->queue_callback(req_id, 0, error_code, 0);
@ -841,7 +846,7 @@ namespace np
rpcn_log.error("Signaling information was requested for a user that doesn't exist or is not online");
return;
}
default: fmt::throw_exception("Unexpected error in reply to RequestSignalingInfos: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to RequestSignalingInfos: %s", error);
}
const auto resp = reply.get_protobuf<np2_structs::SignalingAddr>();
@ -861,9 +866,7 @@ namespace np
const u32 req_id = generate_callback_info(ctx_id, optParam, SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyInfoList, false);
auto cb_info_opt = take_pending_request(req_id);
if (!cb_info_opt)
return true;
ensure (cb_info_opt);
const u32 event_key = get_event_key();
@ -1017,7 +1020,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::NotFound: error_code = SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_BOARD_MASTER_NOT_FOUND; break;
default: fmt::throw_exception("Unexpected error in reply to GetBoardInfos: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to GetBoardInfos: %s", error);
}
if (error_code != CELL_OK)
@ -1091,7 +1094,7 @@ namespace np
score_trans->wake_cond.notify_one();
return;
}
default: fmt::throw_exception("Unexpected error in reply_record_score: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply_record_score: %s", error);
}
auto tmp_rank = reply.get<u32>();
@ -1154,7 +1157,7 @@ namespace np
case rpcn::ErrorType::NotFound: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_STORE_NOT_FOUND); break;
case rpcn::ErrorType::ScoreInvalid: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_INVALID_SCORE); break;
case rpcn::ErrorType::ScoreHasData: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_GAME_DATA_ALREADY_EXISTS); break;
default: fmt::throw_exception("Unexpected error in reply to RecordScoreData: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to RecordScoreData: %s", error);
}
}
@ -1207,7 +1210,7 @@ namespace np
{
case rpcn::ErrorType::NoError: break;
case rpcn::ErrorType::NotFound: score_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_RANKING_GAME_DATA_MASTER_NOT_FOUND); return;
default: fmt::throw_exception("Unexpected error in reply to GetScoreData: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to GetScoreData: %s", error);
}
auto* tdata = std::get_if<tdata_get_score_data>(&score_trans->tdata);
@ -1287,7 +1290,7 @@ namespace np
switch (error)
{
case rpcn::ErrorType::NoError: break;
default: fmt::throw_exception("Unexpected error in GetScoreResponse: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in GetScoreResponse: %s", error);
}
const auto resp = reply.get_protobuf<np2_structs::GetScoreResponse>();
@ -1476,7 +1479,7 @@ namespace np
case rpcn::ErrorType::NotFound: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED); break;
case rpcn::ErrorType::Unauthorized: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN); break;
case rpcn::ErrorType::CondFail: trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED); break;
default: fmt::throw_exception("Unexpected error in handle_tus_no_data: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in handle_tus_no_data: %s", error);
}
}
@ -1499,7 +1502,7 @@ namespace np
case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED);
case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN);
case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED);
default: fmt::throw_exception("Unexpected error in handle_TusVarResponse: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in handle_TusVarResponse: %s", error);
}
const auto resp = reply.get_protobuf<np2_structs::TusVarResponse>();
@ -1555,7 +1558,7 @@ namespace np
case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED);
case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN);
case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED);
default: fmt::throw_exception("Unexpected error in handle_TusVariable: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in handle_TusVariable: %s", error);
}
auto pb_var = reply.get_protobuf<np2_structs::TusVariable>();
@ -1603,7 +1606,7 @@ namespace np
case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED);
case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN);
case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED);
default: fmt::throw_exception("Unexpected error in handle_TusDataStatusResponse: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in handle_TusDataStatusResponse: %s", error);
}
const auto resp = reply.get_protobuf<np2_structs::TusDataStatusResponse>();
@ -1803,7 +1806,7 @@ namespace np
if (!tdata)
{
trans_ctx->tdata = tdata_tus_get_data{.recvSize = recvSize, .dataStatus = dataStatus, .data = data};
const u32 req_id = get_req_id(REQUEST_ID_HIGH::SCORE);
const u32 req_id = get_req_id(REQUEST_ID_HIGH::TUS);
get_rpcn()->tus_get_data(req_id, trans_ctx->communicationId, targetNpId, slotId, vuser);
transaction_async_handler(std::move(lock), trans_ctx, req_id, async);
return;
@ -1844,7 +1847,7 @@ namespace np
case rpcn::ErrorType::NotFound: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_USER_NOT_ASSIGNED);
case rpcn::ErrorType::Unauthorized: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_FORBIDDEN);
case rpcn::ErrorType::CondFail: return tus_trans->set_result_and_wake(SCE_NP_COMMUNITY_SERVER_ERROR_CONDITIONS_NOT_SATISFIED);
default: fmt::throw_exception("Unexpected error in reply to TusGetData: %d", static_cast<u8>(error));
default: fmt::throw_exception("Unexpected error in reply to TusGetData: %s", error);
}
auto pb_data = reply.get_protobuf<np2_structs::TusData>();
@ -1870,6 +1873,7 @@ namespace np
data_status->data = tdata->data;
data_status->dataSize = ::narrow<u32>(pb_data->data().size());
data_status->info.infoSize = ::narrow<u32>(pb_status.info().size());
memcpy(data_status->info.data, pb_data->status().info().data(), std::min(pb_data->status().info().size(), sizeof(data_status->info.data)));
const u32 to_copy = std::min<u32>(data_status->dataSize, tdata->recvSize);
memcpy(data, pb_data->data().data(), to_copy);

View file

@ -303,7 +303,11 @@ namespace np
gui_cache.del_room(room_status->id);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, .edata = std::move(edata)});
{
std::lock_guard lock(gui_notifications.mutex);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, .edata = std::move(edata)});
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_LEAVE_ROOM_DONE, 0);
}
@ -453,7 +457,11 @@ namespace np
extra_nps::print_SceNpMatchingRoom(room_info);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, .edata = std::move(edata)});
{
std::lock_guard lock(gui_notifications.mutex);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, .edata = std::move(edata)});
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_SEARCH_FLAG_DONE, 0);
}
@ -548,7 +556,11 @@ namespace np
extra_nps::print_SceNpMatchingRoom(room_info);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, .edata = std::move(edata)});
{
std::lock_guard lock(gui_notifications.mutex);
gui_notifications.list.emplace(std::make_pair(gui_notifications.current_gui_ctx_id, req_id), gui_notification{.event = SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, .edata = std::move(edata)});
}
ctx->queue_callback(req_id, SCE_NP_MATCHING_EVENT_GET_ROOM_INFO_DONE, 0);
}
@ -581,9 +593,13 @@ namespace np
SceNpRoomId room_id{};
ensure(!resp->id().empty() && resp->id().size() == sizeof(SceNpRoomId::opt));
ctx->wakey = 0;
std::memcpy(room_id.opt, resp->id().data(), sizeof(SceNpRoomId::opt));
const auto [_, inserted] = pending_quickmatching.insert_or_assign(room_id, ctx->ctx_id);
ensure(inserted);
{
std::lock_guard lock(this->mutex_quickmatching);
const auto [_, inserted] = pending_quickmatching.insert_or_assign(room_id, ctx->ctx_id);
ensure(inserted);
}
// Now that the reply has been received, we start the wait for the notification
ctx->thread = std::make_unique<named_thread<std::function<void(SceNpRoomId)>>>("NP GUI Timeout Worker", [ctx, req_id, this](SceNpRoomId room_id)
@ -615,7 +631,6 @@ namespace np
}
});
ctx->wakey = 0;
auto& thread = *ctx->thread;
thread(room_id);
}

View file

@ -1489,7 +1489,7 @@ namespace rpcn
if (error == ErrorType::NoError)
rpcn_log.success("add_friend(\"%s\") succeeded", friend_username);
else
rpcn_log.error("add_friend(\"%s\") failed with error: %s", error);
rpcn_log.error("add_friend(\"%s\") failed with error: %s", friend_username, error);
return error;
}
@ -3085,7 +3085,7 @@ namespace rpcn
}
case NotificationType::FriendPresenceChanged:
{
const std::string username = vdata.get_string(true);
const std::string username = vdata.get_string(false);
SceNpCommunicationId pr_com_id = vdata.get_com_id();
std::string pr_title = fmt::truncate(vdata.get_string(true), SCE_NP_BASIC_PRESENCE_TITLE_SIZE_MAX - 1);
std::string pr_status = fmt::truncate(vdata.get_string(true), SCE_NP_BASIC_PRESENCE_EXTENDED_STATUS_SIZE_MAX - 1);

View file

@ -774,6 +774,7 @@ void signaling_handler::send_information_packets(u32 addr, u16 port, const SceNp
auto& sent_packet = sig_packet;
sent_packet.command = signal_info;
retire_packet(si, signal_info);
send_signaling_packet(sent_packet, addr, port);
queue_signaling_packet(sent_packet, si, steady_clock::now() + REPEAT_INFO_DELAY);
wake_up();

View file

@ -133,7 +133,7 @@ private:
signaling_packet sig_packet{};
std::map<steady_clock::time_point, queued_packet> qpackets; // (wakeup time, packet)
std::multimap<steady_clock::time_point, queued_packet> qpackets; // (wakeup time, packet)
u32 cur_conn_id = 1;
std::unordered_map<std::string, u32> npid_to_conn_id; // (npid, conn_id)

View file

@ -89,12 +89,10 @@ void upnp_handler::upnp_enable()
if (desc_xml)
{
IGDdatas igd_data{};
UPNPUrls igd_urls{};
parserootdesc(desc_xml, desc_xml_size, &igd_data);
parserootdesc(desc_xml, desc_xml_size, &m_igd_data);
free(desc_xml);
desc_xml = nullptr;
GetUPNPUrls(&igd_urls, &igd_data, dev->descURL, 1);
GetUPNPUrls(&m_igd_urls, &m_igd_data, dev->descURL, 1);
upnp_log.notice("Found UPnP device type:%s at %s", dev->st, dev->descURL);
@ -116,24 +114,28 @@ void upnp_handler::upnp_enable()
freeUPNPDevlist(devlist);
}
void upnp_handler::add_port_redir(std::string_view addr, u16 internal_port, std::string_view protocol)
void upnp_handler::add_port_redir(const std::string& addr, u16 internal_port, std::string_view protocol)
{
if (!m_active)
return;
std::lock_guard lock(m_mutex);
u16 external_port = internal_port;
std::string internal_port_str = fmt::format("%d", internal_port);
if (m_bindings[std::string(protocol)].contains(internal_port))
return;
const std::string internal_port_str = fmt::format("%d", internal_port);
const std::string protocol_str(protocol);
const u32 max_port = std::min(static_cast<u32>(internal_port) + 100, 0xFFFFu);
int res = 0;
for (u16 external_port = internal_port; external_port < internal_port + 100; external_port++)
for (u32 external_port = internal_port; external_port <= max_port; external_port++)
{
std::string external_port_str = fmt::format("%d", external_port);
res = UPNP_AddPortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, external_port_str.c_str(), internal_port_str.c_str(), addr.data(), "RPCS3", protocol.data(), nullptr, nullptr);
res = UPNP_AddPortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, external_port_str.c_str(), internal_port_str.c_str(), addr.c_str(), "RPCS3", protocol_str.c_str(), nullptr, nullptr);
if (res == UPNPCOMMAND_SUCCESS)
{
m_bindings[std::string(protocol)][internal_port] = external_port;
m_bindings[protocol_str][static_cast<u16>(internal_port)] = external_port;
upnp_log.notice("Successfully bound %s:%d(%s) to IGD:%d", addr, internal_port, protocol, external_port);
return;
}
@ -146,7 +148,7 @@ void upnp_handler::add_port_redir(std::string_view addr, u16 internal_port, std:
// }
}
upnp_log.error("Failed to bind %s:%d(%s) to IGD:(%d=>%d): %d", addr, internal_port, protocol, internal_port, external_port, res);
upnp_log.error("Failed to bind %s:%d(%s) to IGD:(%d=>%d): %d", addr, internal_port, protocol, internal_port, internal_port, res);
}
void upnp_handler::remove_port_redir(u16 internal_port, std::string_view protocol)
@ -156,27 +158,28 @@ void upnp_handler::remove_port_redir(u16 internal_port, std::string_view protoco
std::lock_guard lock(m_mutex);
const std::string str_protocol(protocol);
const std::string protocol_str(protocol);
if (!m_bindings.contains(str_protocol) || !::at32(m_bindings, str_protocol).contains(internal_port))
if (!m_bindings.contains(protocol_str) || !::at32(m_bindings, protocol_str).contains(internal_port))
{
upnp_log.error("tried to unbind port mapping %d to IGD(%s) but it isn't bound", internal_port, protocol);
return;
}
const u16 external_port = ::at32(::at32(m_bindings, str_protocol), internal_port);
const u16 external_port = ::at32(::at32(m_bindings, protocol_str), internal_port);
remove_port_redir_external(external_port, protocol);
ensure(::at32(m_bindings, str_protocol).erase(internal_port));
ensure(::at32(m_bindings, protocol_str).erase(internal_port));
upnp_log.notice("Successfully deleted port mapping %d to IGD:%d(%s)", internal_port, external_port, protocol);
}
void upnp_handler::remove_port_redir_external(u16 external_port, std::string_view protocol, bool verbose)
{
const std::string str_ext_port = fmt::format("%d", external_port);
const std::string protocol_str(protocol);
if (int res = UPNP_DeletePortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, str_ext_port.c_str(), protocol.data(), nullptr); res != 0 && verbose)
if (int res = UPNP_DeletePortMapping(m_igd_urls.controlURL, m_igd_data.first.servicetype, str_ext_port.c_str(), protocol_str.c_str(), nullptr); res != 0 && verbose)
upnp_log.error("Failed to delete port mapping IGD:%s(%s): %d", str_ext_port, protocol, res);
}

View file

@ -13,7 +13,7 @@ public:
~upnp_handler();
void upnp_enable();
void add_port_redir(std::string_view addr, u16 internal_port, std::string_view protocol);
void add_port_redir(const std::string& addr, u16 internal_port, std::string_view protocol);
void remove_port_redir(u16 internal_port, std::string_view protocol);
bool is_active() const;