/*
* Copyright (c) 2018-2019 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include "../sf_common.hpp"
#include "../sf_service_object.hpp"
#include "../cmif/sf_cmif_pointer_and_size.hpp"
#include "../cmif/sf_cmif_service_object_holder.hpp"
#include "sf_hipc_api.hpp"
namespace sts::sf::hipc {
class ServerSessionManager;
class ServerManagerBase;
class ServerSession : public os::WaitableHolder {
friend class ServerSessionManager;
friend class ServerManagerBase;
NON_COPYABLE(ServerSession);
NON_MOVEABLE(ServerSession);
private:
cmif::ServiceObjectHolder srv_obj_holder;
cmif::PointerAndSize pointer_buffer;
cmif::PointerAndSize saved_message;
std::shared_ptr<::Service> forward_service;
Handle session_handle;
bool is_closed;
bool has_received;
public:
ServerSession(Handle h, cmif::ServiceObjectHolder &&obj) : WaitableHolder(h), srv_obj_holder(std::move(obj)), session_handle(h) {
this->is_closed = false;
this->has_received = false;
this->forward_service = nullptr;
STS_ASSERT(!this->IsMitmSession());
}
ServerSession(Handle h, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) : WaitableHolder(h), srv_obj_holder(std::move(obj)), session_handle(h) {
this->is_closed = false;
this->has_received = false;
this->forward_service = std::move(fsrv);
STS_ASSERT(this->IsMitmSession());
}
bool IsMitmSession() const {
return this->forward_service != nullptr;
}
};
class ServerSessionManager {
private:
template
Result CreateSessionImpl(ServerSession **out, const Constructor &ctor) {
/* Allocate session. */
ServerSession *session_memory = this->AllocateSession();
R_UNLESS(session_memory != nullptr, ResultHipcSessionAllocationFailure);
/* Register session. */
bool succeeded = false;
ON_SCOPE_EXIT {
if (!succeeded) {
this->DestroySession(session_memory);
}
};
R_TRY(ctor(session_memory));
/* Save new session to output. */
succeeded = true;
*out = session_memory;
return ResultSuccess;
}
void DestroySession(ServerSession *session);
Result ProcessRequestImpl(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message);
Result DispatchRequest(cmif::ServiceObjectHolder &&obj, ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message);
virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message);
virtual void RegisterSessionToWaitList(ServerSession *session) = 0;
protected:
virtual ServerSession *AllocateSession() = 0;
virtual void FreeSession(ServerSession *session) = 0;
virtual cmif::PointerAndSize GetSessionPointerBuffer(const ServerSession *session) const = 0;
virtual cmif::PointerAndSize GetSessionSavedMessageBuffer(const ServerSession *session) const = 0;
Result ReceiveRequestImpl(ServerSession *session, const cmif::PointerAndSize &message);
void CloseSessionImpl(ServerSession *session);
Result RegisterSessionImpl(ServerSession *session_memory, Handle session_handle, cmif::ServiceObjectHolder &&obj);
Result AcceptSessionImpl(ServerSession *session_memory, Handle port_handle, cmif::ServiceObjectHolder &&obj);
Result RegisterMitmSessionImpl(ServerSession *session_memory, Handle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
Result AcceptMitmSessionImpl(ServerSession *session_memory, Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
Result ReceiveRequest(ServerSession *session, const cmif::PointerAndSize &message) {
return this->ReceiveRequestImpl(session, message);
}
Result RegisterSession(ServerSession **out, Handle session_handle, cmif::ServiceObjectHolder &&obj) {
auto ctor = [&](ServerSession *session_memory) -> Result {
return this->RegisterSessionImpl(session_memory, session_handle, std::forward(obj));
};
return this->CreateSessionImpl(out, ctor);
}
Result AcceptSession(ServerSession **out, Handle port_handle, cmif::ServiceObjectHolder &&obj) {
auto ctor = [&](ServerSession *session_memory) -> Result {
return this->AcceptSessionImpl(session_memory, port_handle, std::forward(obj));
};
return this->CreateSessionImpl(out, ctor);
}
Result RegisterMitmSession(ServerSession **out, Handle mitm_session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
auto ctor = [&](ServerSession *session_memory) -> Result {
return this->RegisterMitmSessionImpl(session_memory, mitm_session_handle, std::forward(obj), std::forward>(fsrv));
};
return this->CreateSessionImpl(out, ctor);
}
Result AcceptMitmSession(ServerSession **out, Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) {
auto ctor = [&](ServerSession *session_memory) -> Result {
return this->AcceptMitmSessionImpl(session_memory, mitm_port_handle, std::forward(obj), std::forward>(fsrv));
};
return this->CreateSessionImpl(out, ctor);
}
virtual ServerSessionManager *GetSessionManagerByTag(u32 tag) {
/* This is unused. */
return this;
}
public:
Result RegisterSession(Handle session_handle, cmif::ServiceObjectHolder &&obj);
Result AcceptSession(Handle port_handle, cmif::ServiceObjectHolder &&obj);
Result RegisterMitmSession(Handle session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
Result AcceptMitmSession(Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
template
Result AcceptSession(Handle port_handle, std::shared_ptr obj) {
return this->AcceptSession(port_handle, cmif::ServiceObjectHolder(std::move(obj)));
}
template
Result AcceptMitmSession(Handle mitm_port_handle, std::shared_ptr obj, std::shared_ptr<::Service> &&fsrv) {
return this->AcceptMitmSession(mitm_port_handle, cmif::ServiceObjectHolder(std::move(obj)), std::forward>(fsrv));
}
Result ProcessRequest(ServerSession *session, const cmif::PointerAndSize &message);
};
}