Răsfoiți Sursa

friends: INotificationService Implementation of GetEvent (#710)

* friends: INotificationService Implementation of GetEvent

According to the RE, the event isn't signaled when handle is returned.
```C
long nn::friends::detail::service::NotificationService::GetEvent(long this, uint *output_handle)
{
  long inner_struct_event;
  int result;

  if (this->event_created)
  {
    inner_struct_event = &this->event_object;
  }
  else
  {
    inner_struct_event = &this->event_object;
    result = CreateEvent(&this->event_object, 0, 1);

    if ( result )
    {
      Assert();
    }

    this->event_created = true;
  }

  uint event_handle = nn::os::detail::DetachReadableHandleOfInterProcessEvent(inner_struct_event);

  *output_handle = event_handle;
  int unknown = *((char *)output_handle + 4);
  *((char *)output_handle + 4) = 1;

  if (unknown)
  {
    CloseHandle(*output_handle);
  }

  return 0LL;
}
```
Co-Authored-By: Thomas Guillemard <me@thog.eu>
Ac_K 6 ani în urmă
părinte
comite
36f62cbe72

+ 7 - 0
Ryujinx.HLE/HOS/Services/Friend/FriendErr.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.HLE.HOS.Services.Friend
+{
+    static class FriendErr
+    {
+        public const int InvalidArgument = 2;
+    }
+}

+ 26 - 3
Ryujinx.HLE/HOS/Services/Friend/INotificationService.cs

@@ -1,5 +1,8 @@
 using Ryujinx.HLE.HOS.Ipc;
+using Ryujinx.HLE.HOS.Kernel.Common;
+using Ryujinx.HLE.HOS.Kernel.Threading;
 using Ryujinx.HLE.Utilities;
+using System;
 using System.Collections.Generic;
 
 namespace Ryujinx.HLE.HOS.Services.Friend
@@ -8,6 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Friend
     {
         private UInt128 _userId;
 
+        private KEvent _notificationEvent;
+        private int    _notificationEventHandle = 0;
+
         private Dictionary<int, ServiceProcessRequest> _commands;
 
         public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
@@ -16,12 +22,29 @@ namespace Ryujinx.HLE.HOS.Services.Friend
         {
             _commands = new Dictionary<int, ServiceProcessRequest>
             {
-              //{ 0, GetEvent },
-              //{ 1, Pop      },
-              //{ 2, Clear    },
+                { 0, GetEvent }, // 2.0.0+
+              //{ 1, Clear    }, // 2.0.0+
+              //{ 2, Pop      }, // 2.0.0+
             };
 
             _userId = userId;
         }
+
+        public long GetEvent(ServiceCtx context)
+        {
+            if (_notificationEventHandle == 0)
+            {
+                _notificationEvent = new KEvent(context.Device.System);
+
+                if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != KernelResult.Success)
+                {
+                    throw new InvalidOperationException("Out of handles!");
+                }
+            }
+
+            context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle);
+
+            return 0;
+        }
     }
 }

+ 8 - 1
Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs

@@ -2,6 +2,8 @@ using Ryujinx.HLE.HOS.Ipc;
 using Ryujinx.HLE.Utilities;
 using System.Collections.Generic;
 
+using static Ryujinx.HLE.HOS.ErrorCode;
+
 namespace Ryujinx.HLE.HOS.Services.Friend
 {
     class IServiceCreator : IpcService
@@ -33,6 +35,11 @@ namespace Ryujinx.HLE.HOS.Services.Friend
         {
             UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10));
 
+            if (userId.IsNull)
+            {
+                return MakeError(ErrorModule.Friends, FriendErr.InvalidArgument);
+            }
+
             MakeObject(context, new INotificationService(userId));
 
             return 0;
@@ -46,4 +53,4 @@ namespace Ryujinx.HLE.HOS.Services.Friend
             return 0;
         }
     }
-}
+}