diff --git a/nx/include/switch/services/friends.h b/nx/include/switch/services/friends.h index 238e4f1c..2d38893c 100644 --- a/nx/include/switch/services/friends.h +++ b/nx/include/switch/services/friends.h @@ -12,12 +12,12 @@ #include "../sf/service.h" typedef enum { - FriendServiceType_User = 0, ///< Initializes friend:u - FriendServiceType_Viewer = 1, ///< Initializes friend:v - FriendServiceType_Manager = 2, ///< Initializes friend:m - FriendServiceType_System = 3, ///< Initializes friend:s - FriendServiceType_Administrator = 4 ///< Initializes friend:a -} FriendServiceType; + FriendsServiceType_User = 0, ///< Initializes friend:u + FriendsServiceType_Viewer = 1, ///< Initializes friend:v + FriendsServiceType_Manager = 2, ///< Initializes friend:m + FriendsServiceType_System = 3, ///< Initializes friend:s + FriendsServiceType_Administrator = 4 ///< Initializes friend:a +} FriendsServiceType; /// InAppScreenName typedef struct { @@ -49,10 +49,10 @@ typedef struct { char friend_code[0x20]; ///< Friend Code u64 friend_code_next_issuable_time; ///< Unknown char extra[0x7C8]; ///< Extra -} FriendUserSetting; +} FriendsUserSetting; /// Initialize friends -Result friendsInitialize(FriendServiceType service_type); +Result friendsInitialize(FriendsServiceType service_type); /// Exit friends void friendsExit(void); @@ -64,11 +64,11 @@ Service* friendsGetServiceSession(void); Service* friendsGetServiceSession_IFriendsService(void); /** - * @brief Gets the \ref FriendUserSetting details + * @brief Gets the \ref FriendsUserSetting details * @param[in] uid \ref User AccountUid. - * @param[out] user_setting \ref FriendUserSetting + * @param[out] user_setting \ref FriendsUserSetting */ -Result friendsGetUserSetting(AccountUid uid, FriendUserSetting *user_setting); +Result friendsGetUserSetting(AccountUid uid, FriendsUserSetting *user_setting); /** * @brief Gets an Event which is signaled when data is available with \ref friendsTryPopFriendInvitationNotificationInfo. diff --git a/nx/source/services/friends.c b/nx/source/services/friends.c index c713bf80..7d558c3e 100644 --- a/nx/source/services/friends.c +++ b/nx/source/services/friends.c @@ -1,62 +1,125 @@ #include "service_guard.h" +#include "sf/sessionmgr.h" #include "services/friends.h" -static FriendServiceType g_friendsServiceType; +static FriendsServiceType g_friendsServiceType; -static Service g_friendSrv; +static Service g_friendsSrv; static Service g_friendsIFriendService; -NX_GENERATE_SERVICE_GUARD_PARAMS(friends, (FriendServiceType service_type), (service_type)); +static SessionMgr g_friendsSessionMgr; -Result _friendsInitialize(FriendServiceType service_type) { +NX_GENERATE_SERVICE_GUARD_PARAMS(friends, (FriendsServiceType service_type), (service_type)); + +NX_INLINE bool _friendsObjectIsChild(Service* s) { + return s->session == g_friendsSrv.session; +} + +static void _friendsObjectClose(Service* s) { + if (!_friendsObjectIsChild(s)) { + serviceClose(s); + } else { + int slot = sessionmgrAttachClient(&g_friendsSessionMgr); + uint32_t object_id = serviceGetObjectId(s); + + serviceAssumeDomain(s); + cmifMakeCloseRequest(armGetTls(), object_id); + svcSendSyncRequest(sessionmgrGetClientSession(&g_friendsSessionMgr, slot)); + sessionmgrDetachClient(&g_friendsSessionMgr, slot); + } +} + +NX_INLINE Result _friendsObjectDispatchImpl(Service* s, u32 request_id, + const void * in_data, u32 in_data_size, + void * out_data, u32 out_data_size, + SfDispatchParams disp) +{ + int slot = -1; + if (_friendsObjectIsChild(s)) { + slot = sessionmgrAttachClient(&g_friendsSessionMgr); + if (slot < 0) + __builtin_unreachable(); + disp.target_session = sessionmgrGetClientSession(&g_friendsSessionMgr, slot); + serviceAssumeDomain(s); + } + + Result rc = serviceDispatchImpl(s, request_id, in_data, in_data_size, out_data, out_data_size, disp); + + if (slot >= 0) + sessionmgrDetachClient(&g_friendsSessionMgr, slot); + + return rc; +} + +#define _friendsObjectDispatch(_s,_rid,...) \ + _friendsObjectDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ }) + +#define _friendsObjectDispatchIn(_s,_rid,_in,...) \ + _friendsObjectDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ }) + +#define _friendsObjectDispatchOut(_s,_rid,_out,...) \ + _friendsObjectDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }) + +#define _friendsObjectDispatchInOut(_s,_rid,_in,_out,...) \ + _friendsObjectDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }) + +Result _friendsInitialize(FriendsServiceType service_type) { Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); g_friendsServiceType = service_type; switch (g_friendsServiceType) { - case FriendServiceType_User: - rc = smGetService(&g_friendSrv, "friend:u"); + case FriendsServiceType_User: + rc = smGetService(&g_friendsSrv, "friend:u"); break; - case FriendServiceType_Administrator: - rc = smGetService(&g_friendSrv, "friend:a"); + case FriendsServiceType_Administrator: + rc = smGetService(&g_friendsSrv, "friend:a"); break; - case FriendServiceType_Manager: - rc = smGetService(&g_friendSrv, "friend:m"); + case FriendsServiceType_Manager: + rc = smGetService(&g_friendsSrv, "friend:m"); break; - case FriendServiceType_Viewer: - rc = smGetService(&g_friendSrv, "friend:v"); + case FriendsServiceType_Viewer: + rc = smGetService(&g_friendsSrv, "friend:v"); break; - case FriendServiceType_System: - rc = smGetService(&g_friendSrv, "friend:s"); + case FriendsServiceType_System: + rc = smGetService(&g_friendsSrv, "friend:s"); break; } - rc = serviceDispatch(&g_friendSrv, 0, - .out_num_objects = 1, - .out_objects = &g_friendsIFriendService, - ); + if (R_SUCCEEDED(rc)) + rc = serviceConvertToDomain(&g_friendsSrv); + + if (R_SUCCEEDED(rc)) + rc = sessionmgrCreate(&g_friendsSessionMgr, g_friendsSrv.session, 0x5); + + if (R_SUCCEEDED(rc)) { + rc = _friendsObjectDispatch(&g_friendsSrv, 0, + .out_num_objects = 1, + .out_objects = &g_friendsIFriendService + ); + } return rc; } void _friendsCleanup(void) { - serviceClose(&g_friendsIFriendService); - serviceClose(&g_friendSrv); + sessionmgrClose(&g_friendsSessionMgr); + _friendsObjectClose(&g_friendsIFriendService); + serviceClose(&g_friendsSrv); } Service* friendsGetServiceSession(void) { - return &g_friendSrv; + return &g_friendsSrv; } -Service* friendsGetServiceSession_IFriendsService(void) -{ +Service* friendsGetServiceSession_IFriendsService(void) { return &g_friendsIFriendService; } -Result friendsGetUserSetting(AccountUid uid, FriendUserSetting *user_setting) { - return serviceDispatchIn(&g_friendsIFriendService, 20800, uid, +Result friendsGetUserSetting(AccountUid uid, FriendsUserSetting *user_setting) { + return _friendsObjectDispatchIn(&g_friendsIFriendService, 20800, uid, .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_Out | SfBufferAttr_FixedSize }, - .buffers = { { user_setting, sizeof(FriendUserSetting) } } + .buffers = { { user_setting, sizeof(FriendsUserSetting) } } ); }