public void MainLoop() { // Init socket // var socketFileDescriptorFlags = Check(Fcntl(UdpSocket, F_GETFL, 0)); // Check(Fcntl(socketFileDescriptor, F_SETFL, socketFileDescriptorFlags | O_NONBLOCK)); _logger.LogInformation("Start listening on {bindAddress}:{bindPort}", ListenEndPoint.Address, ListenEndPoint.Port); // Register to server Register(); // Create epoll const int maxEvents = 64; using var epollFileDescriptor = EpollCreate(); // Add tun to epoll var tunEpollEvent = new EpollEvent(); tunEpollEvent.events = EpollEvents.EPOLLIN | EpollEvents.EPOLLOUT; tunEpollEvent.fd = (int)Tun.TunFileDescriptor.DangerousGetHandle().ToInt64(); Check(EpollCtl(epollFileDescriptor, EPOLL_CTL_ADD, Tun.TunFileDescriptor, ref tunEpollEvent)); // Add UDP socket to epoll var socketEpollEvent = new EpollEvent(); socketEpollEvent.events = EpollEvents.EPOLLIN | EpollEvents.EPOLLOUT; tunEpollEvent.fd = (int)UdpSocket.SocketFileDescriptor.DangerousGetHandle().ToInt64(); Check(EpollCtl(epollFileDescriptor, EPOLL_CTL_ADD, UdpSocket.SocketFileDescriptor, ref socketEpollEvent)); // main loop Message message; IPEndPoint remote; TunFrame tunFrame; var epollReceivedEvents = new EpollEvent[maxEvents]; while (true) { var epollWaitRet = Check(EpollWait(epollFileDescriptor, epollReceivedEvents, maxEvents, -1)); for (var i = 0; i < epollWaitRet; i++) { var fd = epollReceivedEvents[i].fd; if (epollReceivedEvents[i].events == EpollEvents.EPOLLIN) { if (fd == Tun.TunFileDescriptor) { var data = Tun.Read(BufferSize); TunnelSendQueue.Enqueue(new TunFrame(data)); } else if (fd == UdpSocket.SocketFileDescriptor) { var data = UdpSocket.Recv(BufferSize, out remote); message = DeserializeMessage(data); ListenDispatch(message, remote); } else { throw new AliceException("Unexpected file descriptor"); } } else if (epollReceivedEvents[i].events == EpollEvents.EPOLLOUT) { if (fd == Tun.TunFileDescriptor) { if (TunnelReceiveQueue.TryDequeue(out tunFrame)) { Tun.Write(tunFrame.FrameData); } } else if (fd == UdpSocket.SocketFileDescriptor) { if (TunnelSendQueue.TryDequeue(out tunFrame)) { SendTunnel(tunFrame); } } } } } }