// Poll(u32 nfds, u32 timeout, buffer<unknown, 0x21, 0> fds) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>) public ResultCode Poll(ServiceCtx context) { int fdsCount = context.RequestData.ReadInt32(); int timeout = context.RequestData.ReadInt32(); (long bufferPosition, long bufferSize) = context.Request.GetBufferType0x21(); if (timeout < -1 || fdsCount < 0 || (fdsCount * 8) > bufferSize) { return(WriteBsdResult(context, -1, LinuxError.EINVAL)); } PollEvent[] events = new PollEvent[fdsCount]; for (int i = 0; i < fdsCount; i++) { int socketFd = context.Memory.ReadInt32(bufferPosition + i * 8); BsdSocket socket = RetrieveSocket(socketFd); if (socket == null) { return(WriteBsdResult(context, -1, LinuxError.EBADF)); } PollEvent.EventTypeMask inputEvents = (PollEvent.EventTypeMask)context.Memory.ReadInt16(bufferPosition + i * 8 + 4); PollEvent.EventTypeMask outputEvents = (PollEvent.EventTypeMask)context.Memory.ReadInt16(bufferPosition + i * 8 + 6); events[i] = new PollEvent(socketFd, socket, inputEvents, outputEvents); } List <Socket> readEvents = new List <Socket>(); List <Socket> writeEvents = new List <Socket>(); List <Socket> errorEvents = new List <Socket>(); foreach (PollEvent Event in events) { bool isValidEvent = false; if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) { readEvents.Add(Event.Socket.Handle); errorEvents.Add(Event.Socket.Handle); isValidEvent = true; } if ((Event.InputEvents & PollEvent.EventTypeMask.UrgentInput) != 0) { readEvents.Add(Event.Socket.Handle); errorEvents.Add(Event.Socket.Handle); isValidEvent = true; } if ((Event.InputEvents & PollEvent.EventTypeMask.Output) != 0) { writeEvents.Add(Event.Socket.Handle); errorEvents.Add(Event.Socket.Handle); isValidEvent = true; } if ((Event.InputEvents & PollEvent.EventTypeMask.Error) != 0) { errorEvents.Add(Event.Socket.Handle); isValidEvent = true; } if (!isValidEvent) { Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Poll input event type: {Event.InputEvents}"); return(WriteBsdResult(context, -1, LinuxError.EINVAL)); } } try { System.Net.Sockets.Socket.Select(readEvents, writeEvents, errorEvents, timeout); } catch (SocketException exception) { return(WriteWinSock2Error(context, (WsaError)exception.ErrorCode)); } for (int i = 0; i < fdsCount; i++) { PollEvent Event = events[i]; context.Memory.WriteInt32(bufferPosition + i * 8, Event.SocketFd); context.Memory.WriteInt16(bufferPosition + i * 8 + 4, (short)Event.InputEvents); PollEvent.EventTypeMask outputEvents = 0; Socket socket = Event.Socket.Handle; if (errorEvents.Contains(socket)) { outputEvents |= PollEvent.EventTypeMask.Error; if (!socket.Connected || !socket.IsBound) { outputEvents |= PollEvent.EventTypeMask.Disconnected; } } if (readEvents.Contains(socket)) { if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) { outputEvents |= PollEvent.EventTypeMask.Input; } } if (writeEvents.Contains(socket)) { outputEvents |= PollEvent.EventTypeMask.Output; } context.Memory.WriteInt16(bufferPosition + i * 8 + 6, (short)outputEvents); } return(WriteBsdResult(context, readEvents.Count + writeEvents.Count + errorEvents.Count, LinuxError.SUCCESS)); }
// Poll(u32 nfds, u32 timeout, buffer<unknown, 0x21, 0> fds) -> (i32 ret, u32 bsd_errno, buffer<unknown, 0x22, 0>) public long Poll(ServiceCtx Context) { int FdsCount = Context.RequestData.ReadInt32(); int Timeout = Context.RequestData.ReadInt32(); (long BufferPosition, long BufferSize) = Context.Request.GetBufferType0x21(); if (Timeout < -1 || FdsCount < 0 || (FdsCount * 8) > BufferSize) { return(WriteBsdResult(Context, -1, LinuxError.EINVAL)); } PollEvent[] Events = new PollEvent[FdsCount]; for (int i = 0; i < FdsCount; i++) { int SocketFd = Context.Memory.ReadInt32(BufferPosition + i * 8); BsdSocket Socket = RetrieveSocket(SocketFd); if (Socket == null) { return(WriteBsdResult(Context, -1, LinuxError.EBADF)); } PollEvent.EventTypeMask InputEvents = (PollEvent.EventTypeMask)Context.Memory.ReadInt16(BufferPosition + i * 8 + 4); PollEvent.EventTypeMask OutputEvents = (PollEvent.EventTypeMask)Context.Memory.ReadInt16(BufferPosition + i * 8 + 6); Events[i] = new PollEvent(SocketFd, Socket, InputEvents, OutputEvents); } List <Socket> ReadEvents = new List <Socket>(); List <Socket> WriteEvents = new List <Socket>(); List <Socket> ErrorEvents = new List <Socket>(); foreach (PollEvent Event in Events) { bool IsValidEvent = false; if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) { ReadEvents.Add(Event.Socket.Handle); ErrorEvents.Add(Event.Socket.Handle); IsValidEvent = true; } if ((Event.InputEvents & PollEvent.EventTypeMask.UrgentInput) != 0) { ReadEvents.Add(Event.Socket.Handle); ErrorEvents.Add(Event.Socket.Handle); IsValidEvent = true; } if ((Event.InputEvents & PollEvent.EventTypeMask.Output) != 0) { WriteEvents.Add(Event.Socket.Handle); ErrorEvents.Add(Event.Socket.Handle); IsValidEvent = true; } if ((Event.InputEvents & PollEvent.EventTypeMask.Error) != 0) { ErrorEvents.Add(Event.Socket.Handle); IsValidEvent = true; } if (!IsValidEvent) { Logger.PrintWarning(LogClass.ServiceBsd, $"Unsupported Poll input event type: {Event.InputEvents}"); return(WriteBsdResult(Context, -1, LinuxError.EINVAL)); } } try { System.Net.Sockets.Socket.Select(ReadEvents, WriteEvents, ErrorEvents, Timeout); } catch (SocketException Exception) { return(WriteWinSock2Error(Context, (WSAError)Exception.ErrorCode)); } for (int i = 0; i < FdsCount; i++) { PollEvent Event = Events[i]; Context.Memory.WriteInt32(BufferPosition + i * 8, Event.SocketFd); Context.Memory.WriteInt16(BufferPosition + i * 8 + 4, (short)Event.InputEvents); PollEvent.EventTypeMask OutputEvents = 0; Socket Socket = Event.Socket.Handle; if (ErrorEvents.Contains(Socket)) { OutputEvents |= PollEvent.EventTypeMask.Error; if (!Socket.Connected || !Socket.IsBound) { OutputEvents |= PollEvent.EventTypeMask.Disconnected; } } if (ReadEvents.Contains(Socket)) { if ((Event.InputEvents & PollEvent.EventTypeMask.Input) != 0) { OutputEvents |= PollEvent.EventTypeMask.Input; } } if (WriteEvents.Contains(Socket)) { OutputEvents |= PollEvent.EventTypeMask.Output; } Context.Memory.WriteInt16(BufferPosition + i * 8 + 6, (short)OutputEvents); } return(WriteBsdResult(Context, ReadEvents.Count + WriteEvents.Count + ErrorEvents.Count, LinuxError.SUCCESS)); }