ManagedSocketPollManager.cs
1 using Ryujinx.Common.Logging; 2 using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Types; 3 using System.Collections.Generic; 4 using System.Net.Sockets; 5 6 namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl 7 { 8 class ManagedSocketPollManager : IPollManager 9 { 10 private static ManagedSocketPollManager _instance; 11 12 public static ManagedSocketPollManager Instance 13 { 14 get 15 { 16 _instance ??= new ManagedSocketPollManager(); 17 18 return _instance; 19 } 20 } 21 22 public bool IsCompatible(PollEvent evnt) 23 { 24 return evnt.FileDescriptor is ManagedSocket; 25 } 26 27 public LinuxError Poll(List<PollEvent> events, int timeoutMilliseconds, out int updatedCount) 28 { 29 List<Socket> readEvents = new(); 30 List<Socket> writeEvents = new(); 31 List<Socket> errorEvents = new(); 32 33 updatedCount = 0; 34 35 foreach (PollEvent evnt in events) 36 { 37 ManagedSocket socket = (ManagedSocket)evnt.FileDescriptor; 38 39 bool isValidEvent = evnt.Data.InputEvents == 0; 40 41 errorEvents.Add(socket.Socket); 42 43 if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0) 44 { 45 readEvents.Add(socket.Socket); 46 47 isValidEvent = true; 48 } 49 50 if ((evnt.Data.InputEvents & PollEventTypeMask.UrgentInput) != 0) 51 { 52 readEvents.Add(socket.Socket); 53 54 isValidEvent = true; 55 } 56 57 if ((evnt.Data.InputEvents & PollEventTypeMask.Output) != 0) 58 { 59 writeEvents.Add(socket.Socket); 60 61 isValidEvent = true; 62 } 63 64 if (!isValidEvent) 65 { 66 Logger.Warning?.Print(LogClass.ServiceBsd, $"Unsupported Poll input event type: {evnt.Data.InputEvents}"); 67 return LinuxError.EINVAL; 68 } 69 } 70 71 try 72 { 73 int actualTimeoutMicroseconds = timeoutMilliseconds == -1 ? -1 : timeoutMilliseconds * 1000; 74 75 Socket.Select(readEvents, writeEvents, errorEvents, actualTimeoutMicroseconds); 76 } 77 catch (SocketException exception) 78 { 79 return WinSockHelper.ConvertError((WsaError)exception.ErrorCode); 80 } 81 82 foreach (PollEvent evnt in events) 83 { 84 Socket socket = ((ManagedSocket)evnt.FileDescriptor).Socket; 85 86 PollEventTypeMask outputEvents = evnt.Data.OutputEvents & ~evnt.Data.InputEvents; 87 88 if (errorEvents.Contains(socket)) 89 { 90 outputEvents |= PollEventTypeMask.Error; 91 92 if (!socket.Connected || !socket.IsBound) 93 { 94 outputEvents |= PollEventTypeMask.Disconnected; 95 } 96 } 97 98 if (readEvents.Contains(socket)) 99 { 100 if ((evnt.Data.InputEvents & PollEventTypeMask.Input) != 0) 101 { 102 outputEvents |= PollEventTypeMask.Input; 103 } 104 } 105 106 if (writeEvents.Contains(socket)) 107 { 108 outputEvents |= PollEventTypeMask.Output; 109 } 110 111 evnt.Data.OutputEvents = outputEvents; 112 } 113 114 updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count; 115 116 return LinuxError.SUCCESS; 117 } 118 119 public LinuxError Select(List<PollEvent> events, int timeout, out int updatedCount) 120 { 121 List<Socket> readEvents = new(); 122 List<Socket> writeEvents = new(); 123 List<Socket> errorEvents = new(); 124 125 updatedCount = 0; 126 127 foreach (PollEvent pollEvent in events) 128 { 129 ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor; 130 131 if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Input)) 132 { 133 readEvents.Add(socket.Socket); 134 } 135 136 if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Output)) 137 { 138 writeEvents.Add(socket.Socket); 139 } 140 141 if (pollEvent.Data.InputEvents.HasFlag(PollEventTypeMask.Error)) 142 { 143 errorEvents.Add(socket.Socket); 144 } 145 } 146 147 Socket.Select(readEvents, writeEvents, errorEvents, timeout); 148 149 updatedCount = readEvents.Count + writeEvents.Count + errorEvents.Count; 150 151 foreach (PollEvent pollEvent in events) 152 { 153 ManagedSocket socket = (ManagedSocket)pollEvent.FileDescriptor; 154 155 if (readEvents.Contains(socket.Socket)) 156 { 157 pollEvent.Data.OutputEvents |= PollEventTypeMask.Input; 158 } 159 160 if (writeEvents.Contains(socket.Socket)) 161 { 162 pollEvent.Data.OutputEvents |= PollEventTypeMask.Output; 163 } 164 165 if (errorEvents.Contains(socket.Socket)) 166 { 167 pollEvent.Data.OutputEvents |= PollEventTypeMask.Error; 168 } 169 } 170 171 return LinuxError.SUCCESS; 172 } 173 } 174 }