Stratosphere: ServiceServer<T> -> IServer<T> as abstract base class.

This commit is contained in:
Michael Scire 2018-04-21 20:57:24 -06:00
parent 4aa93ad354
commit 044d367eda
5 changed files with 144 additions and 112 deletions

View file

@ -1,8 +1,11 @@
#pragma once #pragma once
#include "stratosphere/ipc_templating.hpp"
#include "stratosphere/iwaitable.hpp" #include "stratosphere/iwaitable.hpp"
#include "stratosphere/iserviceobject.hpp" #include "stratosphere/iserviceobject.hpp"
#include "stratosphere/iserver.hpp"
#include "stratosphere/servicesession.hpp" #include "stratosphere/servicesession.hpp"
#include "stratosphere/serviceserver.hpp" #include "stratosphere/serviceserver.hpp"
#include "stratosphere/managedportserver.hpp"
#include "stratosphere/waitablemanager.hpp" #include "stratosphere/waitablemanager.hpp"
#include "stratosphere/ipc_templating.hpp"

View file

@ -0,0 +1,115 @@
#pragma once
#include <switch.h>
#include <type_traits>
#include "iserviceobject.hpp"
#include "iwaitable.hpp"
#include "servicesession.hpp"
template <typename T>
class ServiceSession;
template <typename T>
class IServer : public IWaitable {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
protected:
Handle port_handle;
unsigned int max_sessions;
unsigned int num_sessions;
ServiceSession<T> **sessions;
virtual Result register_self(const char *service_name) {
return smRegisterService(&this->port_handle, service_name, false, this->max_sessions);
}
public:
IServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) {
if (R_FAILED(register_self(service_name))) {
/* TODO: Panic. */
}
this->sessions = new ServiceSession<T> *[this->max_sessions];
for (unsigned int i = 0; i < this->max_sessions; i++) {
this->sessions[i] = NULL;
}
this->num_sessions = 0;
}
virtual ~IServer() {
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
delete this->sessions[i];
}
delete this->sessions;
}
if (port_handle) {
svcCloseHandle(port_handle);
}
}
/* IWaitable */
virtual unsigned int get_num_waitables() {
unsigned int n = 1;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
n += this->sessions[i]->get_num_waitables();
}
}
return n;
}
virtual void get_waitables(IWaitable **dst) {
dst[0] = this;
unsigned int n = 0;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
this->sessions[i]->get_waitables(&dst[1 + n]);
n += this->sessions[i]->get_num_waitables();
}
}
}
virtual void delete_child(IWaitable *child) {
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == child) {
break;
}
}
if (i == this->max_sessions) {
/* TODO: Panic, because this isn't our child. */
} else {
delete this->sessions[i];
this->sessions[i] = NULL;
this->num_sessions--;
}
}
virtual Handle get_handle() {
return this->port_handle;
}
virtual Result handle_signaled(u64 timeout) {
/* If this server's port was signaled, accept a new session. */
Handle session_h;
svcAcceptSession(&session_h, this->port_handle);
if (this->num_sessions >= this->max_sessions) {
svcCloseHandle(session_h);
return 0x10601;
}
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == NULL) {
break;
}
}
this->sessions[i] = new ServiceSession<T>(this, session_h, 0);
this->sessions[i]->set_parent(this);
this->num_sessions++;
return 0;
}
};

View file

@ -0,0 +1,13 @@
#pragma once
#include <switch.h>
#include "iserver.hpp"
template <typename T>
class ManagedPortServer : public IServer<T> {
private:
virtual Result register_self(const char *service_name) {
return svcManageNamedPort(&this->port_handle, service_name, this->max_sessions);
}
public:
ManagedPortServer(const char *service_name, unsigned int max_s) : IServer<T>(service_name, max_s) { }
};

View file

@ -1,112 +1,13 @@
#pragma once #pragma once
#include <switch.h> #include <switch.h>
#include <type_traits> #include "iserver.hpp"
#include "iserviceobject.hpp"
#include "iwaitable.hpp"
#include "servicesession.hpp"
template <typename T> template <typename T>
class ServiceSession; class ServiceServer : public IServer<T> {
private:
template <typename T> virtual Result register_self(const char *service_name) {
class ServiceServer : public IWaitable { return smRegisterService(&this->port_handle, service_name, false, this->max_sessions);
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); }
Handle port_handle;
unsigned int max_sessions;
unsigned int num_sessions;
ServiceSession<T> **sessions;
public: public:
ServiceServer(const char *service_name, unsigned int max_s) : max_sessions(max_s) { ServiceServer(const char *service_name, unsigned int max_s) : IServer<T>(service_name, max_s) { }
if (R_FAILED(smRegisterService(&this->port_handle, service_name, false, this->max_sessions))) {
/* TODO: Panic. */
}
this->sessions = new ServiceSession<T> *[this->max_sessions];
for (unsigned int i = 0; i < this->max_sessions; i++) {
this->sessions[i] = NULL;
}
this->num_sessions = 0;
}
virtual ~ServiceServer() {
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
delete this->sessions[i];
}
delete this->sessions;
}
if (port_handle) {
svcCloseHandle(port_handle);
}
}
/* IWaitable */
virtual unsigned int get_num_waitables() {
unsigned int n = 1;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
n += this->sessions[i]->get_num_waitables();
}
}
return n;
}
virtual void get_waitables(IWaitable **dst) {
dst[0] = this;
unsigned int n = 0;
for (unsigned int i = 0; i < this->max_sessions; i++) {
if (this->sessions[i]) {
this->sessions[i]->get_waitables(&dst[1 + n]);
n += this->sessions[i]->get_num_waitables();
}
}
}
virtual void delete_child(IWaitable *child) {
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == child) {
break;
}
}
if (i == this->max_sessions) {
/* TODO: Panic, because this isn't our child. */
} else {
delete this->sessions[i];
this->sessions[i] = NULL;
this->num_sessions--;
}
}
virtual Handle get_handle() {
return this->port_handle;
}
virtual Result handle_signaled(u64 timeout) {
/* If this server's port was signaled, accept a new session. */
Handle session_h;
svcAcceptSession(&session_h, this->port_handle);
if (this->num_sessions >= this->max_sessions) {
svcCloseHandle(session_h);
return 0x10601;
}
unsigned int i;
for (i = 0; i < this->max_sessions; i++) {
if (this->sessions[i] == NULL) {
break;
}
}
this->sessions[i] = new ServiceSession<T>(this, session_h, 0);
this->sessions[i]->set_parent(this);
this->num_sessions++;
return 0;
}
}; };

View file

@ -5,7 +5,7 @@
#include "ipc_templating.hpp" #include "ipc_templating.hpp"
#include "iserviceobject.hpp" #include "iserviceobject.hpp"
#include "iwaitable.hpp" #include "iwaitable.hpp"
#include "serviceserver.hpp" #include "iserver.hpp"
enum IpcControlCommand { enum IpcControlCommand {
IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0, IpcCtrl_Cmd_ConvertCurrentObjectToDomain = 0,
@ -18,14 +18,14 @@ enum IpcControlCommand {
#define POINTER_BUFFER_SIZE_MAX 0xFFFF #define POINTER_BUFFER_SIZE_MAX 0xFFFF
template <typename T> template <typename T>
class ServiceServer; class IServer;
template <typename T> template <typename T>
class ServiceSession : public IWaitable { class ServiceSession : public IWaitable {
static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject"); static_assert(std::is_base_of<IServiceObject, T>::value, "Service Objects must derive from IServiceObject");
T *service_object; T *service_object;
ServiceServer<T> *server; IServer<T> *server;
Handle server_handle; Handle server_handle;
Handle client_handle; Handle client_handle;
char pointer_buffer[0x400]; char pointer_buffer[0x400];
@ -33,7 +33,7 @@ class ServiceSession : public IWaitable {
static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!"); static_assert(sizeof(pointer_buffer) <= POINTER_BUFFER_SIZE_MAX, "Incorrect Size for PointerBuffer!");
public: public:
ServiceSession<T>(ServiceServer<T> *s, Handle s_h, Handle c_h) : server(s), server_handle(s_h), client_handle(c_h) { ServiceSession<T>(IServer<T> *s, Handle s_h, Handle c_h) : server(s), server_handle(s_h), client_handle(c_h) {
this->service_object = new T(); this->service_object = new T();
} }