mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
313 lines
8.9 KiB
C
313 lines
8.9 KiB
C
/**
|
|
* @file sm.h
|
|
* @brief Service manager (sm) IPC wrapper.
|
|
* @author plutoo
|
|
* @author yellows8
|
|
* @copyright libnx Authors
|
|
*/
|
|
#pragma once
|
|
#include "../types.h"
|
|
#include "../kernel/svc.h"
|
|
#include "../kernel/ipc.h"
|
|
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
|
|
/// Service type.
|
|
typedef enum {
|
|
ServiceType_Uninitialized, ///< Uninitialized service.
|
|
ServiceType_Normal, ///< Normal service.
|
|
ServiceType_Domain, ///< Domain.
|
|
ServiceType_DomainSubservice, ///< Domain subservice;
|
|
ServiceType_Override, ///< Service overriden in the homebrew environment.
|
|
} ServiceType;
|
|
|
|
/// Service object structure.
|
|
typedef struct {
|
|
Handle handle;
|
|
u32 object_id;
|
|
ServiceType type;
|
|
} Service;
|
|
|
|
/**
|
|
* @brief Returns whether a service is overriden in the homebrew environment.
|
|
* @param[in] s Service object.
|
|
* @return true if overriden.
|
|
*/
|
|
static inline bool serviceIsOverride(Service* s) {
|
|
return s->type == ServiceType_Override;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns whether a service has been initialized.
|
|
* @param[in] s Service object.
|
|
* @return true if initialized.
|
|
*/
|
|
static inline bool serviceIsActive(Service* s) {
|
|
return s->type != ServiceType_Uninitialized;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns whether a service is a domain.
|
|
* @param[in] s Service object.
|
|
* @return true if a domain.
|
|
*/
|
|
static inline bool serviceIsDomain(Service* s) {
|
|
return s->type == ServiceType_Domain;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns whether a service is a domain subservice.
|
|
* @param[in] s Service object.
|
|
* @return true if a domain subservice.
|
|
*/
|
|
static inline bool serviceIsDomainSubservice(Service* s) {
|
|
return s->type == ServiceType_DomainSubservice;
|
|
}
|
|
|
|
/**
|
|
* @brief For a domain/domain subservice, return the associated object ID.
|
|
* @param[in] s Service object, necessarily a domain or domain subservice.
|
|
* @return The object ID.
|
|
*/
|
|
static inline u32 serviceGetObjectId(Service* s) {
|
|
return s->object_id;
|
|
}
|
|
|
|
/**
|
|
* @brief Closes a domain object by ID.
|
|
* @param[in] s Service object, necessarily a domain or domain subservice.
|
|
* @param object_id ID of the object to close.
|
|
* @return Result code.
|
|
*/
|
|
DEPRECATED
|
|
static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
|
|
return ipcCloseObjectById(s->handle, object_id);
|
|
}
|
|
|
|
/**
|
|
* @brief Dispatches an IPC request to a service.
|
|
* @param[in] s Service object.
|
|
* @return Result code.
|
|
*/
|
|
DEPRECATED
|
|
static inline Result serviceIpcDispatch(Service* s) {
|
|
return ipcDispatch(s->handle);
|
|
}
|
|
|
|
/**
|
|
* @brief Creates a service object from an IPC session handle.
|
|
* @param[out] s Service object.
|
|
* @param[in] h IPC session handle.
|
|
*/
|
|
static inline void serviceCreate(Service* s, Handle h) {
|
|
s->handle = h;
|
|
s->type = ServiceType_Normal;
|
|
s->object_id = IPC_INVALID_OBJECT_ID;
|
|
}
|
|
|
|
/**
|
|
* @brief Creates a domain subservice object from a parent service.
|
|
* @param[out] s Service object.
|
|
* @param[in] parent Parent service, necessarily a domain or domain subservice.
|
|
* @param[in] object_id Object ID for this subservice.
|
|
*/
|
|
static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id) {
|
|
s->handle = parent->handle;
|
|
s->type = ServiceType_DomainSubservice;
|
|
s->object_id = object_id;
|
|
}
|
|
|
|
/**
|
|
* @brief Creates a subservice object from a parent service.
|
|
* @param[out] s Service object.
|
|
* @param[in] parent Parent service, possibly a domain or domain subservice.
|
|
* @param[in] r Parsed IPC command containing handles/object IDs to create subservice from.
|
|
* @param[in] i The index of the handle/object ID to create subservice from.
|
|
*/
|
|
DEPRECATED
|
|
static inline void serviceCreateSubservice(Service* s, Service* parent, IpcParsedCommand* r, int i) {
|
|
if (r->IsDomainResponse) {
|
|
return serviceCreateDomainSubservice(s, parent, r->OutObjectIds[i]);
|
|
} else {
|
|
return serviceCreate(s, r->Handles[i]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Sends a service object with the specified cmd. This only supports domains.
|
|
* @param[in] s Service object to send.
|
|
* @param[in] cmd IPC command structure.
|
|
*/
|
|
DEPRECATED
|
|
static inline void serviceSendObject(Service* s, IpcCommand* cmd) {
|
|
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
|
ipcSendObjectId(cmd, s->object_id);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Converts a regular service to a domain.
|
|
* @param[in] s Service object.
|
|
* @return Result code.
|
|
*/
|
|
static inline Result serviceConvertToDomain(Service* s) {
|
|
Result rc = 0;
|
|
if (serviceIsOverride(s)) {
|
|
rc = ipcCloneSession(s->handle, 1, &s->handle);
|
|
if (R_FAILED(rc)) {
|
|
return rc;
|
|
}
|
|
s->type = ServiceType_Normal;
|
|
}
|
|
rc = ipcConvertSessionToDomain(s->handle, &s->object_id);
|
|
if (R_SUCCEEDED(rc)) {
|
|
s->type = ServiceType_Domain;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/**
|
|
* @brief Closes a service.
|
|
* @param[in] s Service object.
|
|
*/
|
|
static inline void serviceClose(Service* s) {
|
|
switch (s->type) {
|
|
|
|
case ServiceType_Normal:
|
|
case ServiceType_Domain:
|
|
ipcCloseSession(s->handle);
|
|
svcCloseHandle(s->handle);
|
|
break;
|
|
|
|
case ServiceType_DomainSubservice:
|
|
serviceCloseObjectById(s, s->object_id);
|
|
break;
|
|
|
|
case ServiceType_Override:
|
|
// Don't close because we don't own the overridden handle.
|
|
break;
|
|
|
|
case ServiceType_Uninitialized:
|
|
break;
|
|
}
|
|
|
|
s->type = ServiceType_Uninitialized;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Prepares the header of an IPC command structure for a service.
|
|
* @param s Service to prepare message header for
|
|
* @param cmd IPC command structure.
|
|
* @param sizeof_raw Size in bytes of the raw data structure to embed inside the IPC request
|
|
* @return Pointer to the raw embedded data structure in the request, ready to be filled out.
|
|
*/
|
|
DEPRECATED
|
|
static inline void* serviceIpcPrepareHeader(Service* s, IpcCommand* cmd, size_t sizeof_raw) {
|
|
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
|
return ipcPrepareHeaderForDomain(cmd, sizeof_raw, serviceGetObjectId(s));
|
|
} else {
|
|
return ipcPrepareHeader(cmd, sizeof_raw);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Parse an IPC command response into an IPC parsed command structure for a service.
|
|
* @param s Service to prepare message header for
|
|
* @param r IPC parsed command structure to fill in.
|
|
* @param sizeof_raw Size in bytes of the raw data structure.
|
|
* @return Result code.
|
|
*/
|
|
DEPRECATED
|
|
static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t sizeof_raw) {
|
|
if (serviceIsDomain(s) || serviceIsDomainSubservice(s)) {
|
|
return ipcParseDomainResponse(r, sizeof_raw);
|
|
} else {
|
|
return ipcParse(r);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Initializes SM.
|
|
* @return Result code.
|
|
* @note This function is already called in the default application startup code (before main() is called).
|
|
*/
|
|
Result smInitialize(void);
|
|
|
|
/**
|
|
* @brief Uninitializes SM.
|
|
* @return Result code.
|
|
* @note This function is already handled in the default application exit code (after main() returns).
|
|
*/
|
|
void smExit(void);
|
|
|
|
/**
|
|
* @brief Requests a service from SM.
|
|
* @param[out] service_out Service structure which will be filled in.
|
|
* @param[in] name Name of the service to request.
|
|
* @return Result code.
|
|
*/
|
|
Result smGetService(Service* service_out, const char* name);
|
|
|
|
/**
|
|
* @brief Requests a service from SM, as an IPC session handle directly
|
|
* @param[out] handle_out Variable containing IPC session handle.
|
|
* @param[in] name Name of the service to request.
|
|
* @return Result code.
|
|
*/
|
|
Result smGetServiceOriginal(Handle* handle_out, u64 name);
|
|
|
|
/**
|
|
* @brief Retrieves an overriden service in the homebrew environment.
|
|
* @param[in] name Name of the service to request (as 64-bit integer).
|
|
* @return IPC session handle.
|
|
*/
|
|
Handle smGetServiceOverride(u64 name);
|
|
|
|
/**
|
|
* @brief Creates and registers a new service within SM.
|
|
* @param[out] handle_out Variable containing IPC port handle.
|
|
* @param[in] name Name of the service.
|
|
* @param[in] is_light "Is light"
|
|
* @param[in] max_sessions Maximum number of concurrent sessions that the service will accept.
|
|
* @return Result code.
|
|
*/
|
|
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions);
|
|
|
|
/**
|
|
* @brief Unregisters a previously registered service in SM.
|
|
* @param[in] name Name of the service.
|
|
* @return Result code.
|
|
*/
|
|
Result smUnregisterService(const char* name);
|
|
|
|
/**
|
|
* @brief Check whether SM is initialized.
|
|
* @return true if initialized.
|
|
*/
|
|
bool smHasInitialized(void);
|
|
|
|
/**
|
|
* @brief Gets the Service session used to communicate with SM.
|
|
* @return Pointer to service session used to communicate with SM.
|
|
*/
|
|
Service *smGetServiceSession(void);
|
|
|
|
/**
|
|
* @brief Encodes a service name as a 64-bit integer.
|
|
* @param[in] name Name of the service.
|
|
* @return Encoded name.
|
|
*/
|
|
u64 smEncodeName(const char* name);
|
|
|
|
/**
|
|
* @brief Overrides a service with a custom IPC service handle.
|
|
* @param[in] name Name of the service (as 64-bit integer).
|
|
* @param[in] handle IPC session handle.
|
|
*/
|
|
void smAddOverrideHandle(u64 name, Handle handle);
|
|
|
|
#pragma GCC diagnostic pop
|