From daecd812b04e90da525e1858c40fd6c0a1e59ede Mon Sep 17 00:00:00 2001 From: Subv Date: Wed, 13 Dec 2017 13:56:53 -0500 Subject: [PATCH] HLE/Services: Allow specifying a SessionData template parameter to ServiceFramework. Some services can have multiple clients at the same time, and they identify the different clients using the server session as a key. This parameter (if present) should be a structure that contains the per-session data for each service. The data can be retrieved using ServiceFramework::GetSessionData(session) --- src/core/hle/kernel/hle_ipc.cpp | 14 +++++++++---- src/core/hle/kernel/hle_ipc.h | 34 ++++++++++++++++++++++++++----- src/core/hle/service/fs/archive.h | 4 ++++ src/core/hle/service/service.h | 16 +++++++++++++-- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 9e45970d1..5b76a92cd 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -2,26 +2,32 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include -#include #include "common/assert.h" #include "common/common_types.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/server_session.h" namespace Kernel { +SessionRequestHandler::SessionInfo::SessionInfo(SharedPtr session, + std::unique_ptr data) + : session(std::move(session)), data(std::move(data)) {} + void SessionRequestHandler::ClientConnected(SharedPtr server_session) { server_session->SetHleHandler(shared_from_this()); - connected_sessions.push_back(server_session); + connected_sessions.emplace_back(std::move(server_session), MakeSessionData()); } void SessionRequestHandler::ClientDisconnected(SharedPtr server_session) { server_session->SetHleHandler(nullptr); - boost::range::remove_erase(connected_sessions, server_session); + connected_sessions.erase( + std::remove_if(connected_sessions.begin(), connected_sessions.end(), + [&](const SessionInfo& info) { return info.session == server_session; }), + connected_sessions.end()); } HLERequestContext::HLERequestContext(SharedPtr session) diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 338f3c7d1..ccff81a21 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -54,13 +55,36 @@ public: * associated ServerSession. * @param server_session ServerSession associated with the connection. */ - virtual void ClientDisconnected(SharedPtr server_session); + void ClientDisconnected(SharedPtr server_session); + + /// Empty placeholder structure for services with no per-session data. The session data classes + /// in each service must inherit from this. + struct SessionDataBase {}; protected: - /// List of sessions that are connected to this handler. - /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list - // for the duration of the connection. - std::vector> connected_sessions; + /// Creates the storage for the session data of the service. + virtual std::unique_ptr MakeSessionData() const = 0; + + /// Returns the session data associated with the server session. + template + T* GetSessionData(SharedPtr session) { + static_assert(std::is_base_of(), + "T is not a subclass of SessionDataBase"); + auto itr = std::find_if(connected_sessions.begin(), connected_sessions.end(), + [&](const SessionInfo& info) { return info.session == session; }); + ASSERT(itr != connected_sessions.end()); + return static_cast(itr->data.get()); + } + + struct SessionInfo { + SessionInfo(SharedPtr session, std::unique_ptr data); + + SharedPtr session; + std::unique_ptr data; + }; + /// List of sessions that are connected to this handler. A ServerSession whose server endpoint + /// is an HLE implementation is kept alive by this list for the duration of the connection. + std::vector connected_sessions; }; class MappedBuffer { diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 01d67c3d0..65f6f207a 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -108,6 +108,10 @@ public: protected: void HandleSyncRequest(Kernel::SharedPtr server_session) override; + + std::unique_ptr MakeSessionData() const override { + return nullptr; + } }; /** diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 084994816..26894ce25 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -87,6 +87,10 @@ public: protected: void HandleSyncRequest(Kernel::SharedPtr server_session) override; + std::unique_ptr MakeSessionData() const override { + return nullptr; + } + /** * Registers the functions in the service */ @@ -144,7 +148,7 @@ protected: using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&); private: - template + template friend class ServiceFramework; struct FunctionInfoBase { @@ -190,7 +194,7 @@ private: * of the passed in function pointers and then delegate the actual work to the implementation in the * base class. */ -template +template class ServiceFramework : public ServiceFrameworkBase { protected: /// Contains information about a request type which is handled by the service. @@ -236,6 +240,14 @@ protected: RegisterHandlersBase(functions, n); } + std::unique_ptr MakeSessionData() const override { + return std::make_unique(); + } + + SessionData* GetSessionData(Kernel::SharedPtr server_session) { + return ServiceFrameworkBase::GetSessionData(server_session); + } + private: /** * This function is used to allow invocation of pointers to handlers stored in the base class