protected IoUringConnectionContext(LinuxSocket socket, EndPoint local, EndPoint remote, TransportThreadContext threadContext)
        {
            Socket = socket;

            LocalEndPoint  = local;
            RemoteEndPoint = remote;

            MemoryPool     = threadContext.MemoryPool;
            _threadContext = threadContext;

            var appScheduler  = threadContext.Options.ApplicationSchedulingMode;
            var inputOptions  = new PipeOptions(MemoryPool, appScheduler, PipeScheduler.Inline, PauseInputWriterThreshold, PauseInputWriterThreshold / 2, useSynchronizationContext: false);
            var outputOptions = new PipeOptions(MemoryPool, PipeScheduler.Inline, appScheduler, PauseOutputWriterThreshold, PauseOutputWriterThreshold / 2, useSynchronizationContext: false);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);

            Transport   = pair.Transport;
            Application = pair.Application;

            _onOnFlushedToApp = FlushedToAppAsynchronously;
            _onReadFromApp    = ReadFromAppAsynchronously;

            iovec[] vecs   = new iovec[ReadIOVecCount + WriteIOVecCount];
            var     handle = GCHandle.Alloc(vecs, GCHandleType.Pinned);

            _iovec       = (iovec *)handle.AddrOfPinnedObject();
            _iovecHandle = handle;
        }
Beispiel #2
0
        protected IoUringConnection(LinuxSocket socket, EndPoint local, EndPoint remote, MemoryPool <byte> memoryPool, IoUringOptions options, TransportThreadScheduler scheduler)
        {
            Socket = socket;

            LocalEndPoint  = local;
            RemoteEndPoint = remote;

            MemoryPool = memoryPool;
            Debug.Assert(MaxBufferSize == MemoryPool.MaxBufferSize);

            _scheduler = scheduler;

            _connectionClosedTokenSource = new CancellationTokenSource();
            ConnectionClosed             = _connectionClosedTokenSource.Token;
            _waitForConnectionClosedTcs  = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously);

            var appScheduler  = options.ApplicationSchedulingMode;
            var inputOptions  = new PipeOptions(memoryPool, appScheduler, PipeScheduler.Inline, PauseInputWriterThreshold, PauseInputWriterThreshold / 2, useSynchronizationContext: false);
            var outputOptions = new PipeOptions(memoryPool, PipeScheduler.Inline, appScheduler, PauseOutputWriterThreshold, PauseOutputWriterThreshold / 2, useSynchronizationContext: false);

            var pair = DuplexPipe.CreateConnectionPair(inputOptions, outputOptions);

            Transport   = pair.Transport;
            Application = pair.Application;

            _onOnFlushedToApp = () => HandleFlushedToApp();
            _onReadFromApp    = () => HandleReadFromApp();

            _ioVecBytes = GC.AllocateUninitializedArray <byte>(SizeOf.iovec * (ReadIOVecCount + WriteIOVecCount), pinned: true);
            unsafe
            {
                _iovec = (iovec *)MemoryHelper.UnsafeGetAddressOfPinnedArrayData(_ioVecBytes);
            }
        }
        public RingUnblockHandle(Ring ring)
        {
            _supportsRead     = ring.Supports(RingOperation.Read);
            _supportsFastPoll = ring.SupportsFastPoll;

            int eventfdFlags = EFD_CLOEXEC;

            if (!_supportsFastPoll)
            {
                // Work-around for https://bugzilla.kernel.org/show_bug.cgi?id=208039
                eventfdFlags |= EFD_NONBLOCK;
            }

            int res = eventfd(0, eventfdFlags);

            if (res == -1)
            {
                ThrowHelper.ThrowNewErrnoException();
            }
            _eventfd = res;

            if (!_supportsRead)
            {
                _eventfdIoVecBytes = GC.AllocateUninitializedArray <byte>(SizeOf.iovec, pinned: true);
                IoVec->iov_base    = Buffer;
                IoVec->iov_len     = BufferLen;
            }
        }
Beispiel #4
0
        public ValueTask <ConnectionContext> Connect(IPEndPoint endpoint)
        {
            var         domain = endpoint.AddressFamily == AddressFamily.InterNetwork ? AF_INET : AF_INET6;
            LinuxSocket s      = socket(domain, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);

            if (_threadContext.Options.TcpNoDelay)
            {
                s.SetOption(SOL_TCP, TCP_NODELAY, 1);
            }

            var context = new OutboundConnectionContext(s, endpoint, _threadContext);
            var tcs     = new TaskCompletionSource <ConnectionContext>(TaskCreationOptions.RunContinuationsAsynchronously); // Ensure the transport thread doesn't run continuations

            context.ConnectCompletion = tcs;

            endpoint.ToSockAddr(context.Addr, out var addrLength);
            context.AddrLen = addrLength;

            _connections[s] = context;
            Connect(context);

            _threadContext.Notify();

            return(new ValueTask <ConnectionContext>(tcs.Task));
        }
Beispiel #5
0
        private void CompleteAccept(AcceptSocketContext acceptContext, int result)
        {
            if (result < 0)
            {
                var err = -result;
                if (err == EAGAIN || err == EINTR || err == EMFILE)
                {
                    Debug.WriteLine($"accept completed with EAGAIN on {(int)acceptContext.Socket}");
                    Accept(acceptContext);
                    return;
                }

                throw new ErrnoException(err);
            }

            LinuxSocket socket = result;

            Debug.WriteLine($"Accepted {(int)socket} from {(int)acceptContext.Socket}");
            if (_threadContext.Options.TcpNoDelay)
            {
                socket.SetOption(SOL_TCP, TCP_NODELAY, 1);
            }

            var remoteEndpoint = IPEndPointFormatter.AddrToIpEndPoint(acceptContext.Addr);
            var context        = new InboundConnectionContext(socket, acceptContext.EndPoint, remoteEndpoint, _threadContext);

            _connections[socket] = context;
            acceptContext.AcceptQueue.TryWrite(context);

            Accept(acceptContext);
            Read(context);
            ReadFromApp(context);
        }
Beispiel #6
0
        public void Bind(IPEndPoint endpoint, ChannelWriter <ConnectionContext> acceptQueue)
        {
            var         domain = endpoint.AddressFamily == AddressFamily.InterNetwork ? AF_INET : AF_INET6;
            LinuxSocket s      = socket(domain, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);

            s.SetOption(SOL_SOCKET, SO_REUSEADDR, 1);
            s.SetOption(SOL_SOCKET, SO_REUSEPORT, 1);
            s.Bind(endpoint);
            s.Listen(ListenBacklog);

            var context = new AcceptSocketContext(s, endpoint, acceptQueue);

            _acceptSocketQueue.Enqueue(context);
            _threadContext.Notify();
        }
Beispiel #7
0
        public RingUnblockHandle(Ring ring)
        {
            _supportsRead     = ring.Supports(RingOperation.Read);
            _supportsFastPoll = ring.SupportsFastPoll;

            int res = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);

            if (res == -1)
            {
                ThrowHelper.ThrowNewErrnoException();
            }
            _eventfd = res;

            if (!_supportsRead)
            {
                _eventfdIoVecBytes = GC.AllocateUninitializedArray <byte>(SizeOf.iovec, pinned: true);
                IoVec->iov_base    = Buffer;
                IoVec->iov_len     = BufferLen;
            }
        }
Beispiel #8
0
        public ValueTask <ConnectionContext> Connect(IPEndPoint endpoint)
        {
            var         domain = endpoint.AddressFamily == AddressFamily.InterNetwork ? AF_INET : AF_INET6;
            LinuxSocket s      = socket(domain, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);

            if (_threadContext.Options.TcpNoDelay)
            {
                s.SetOption(SOL_TCP, TCP_NODELAY, 1);
            }
            var context = new OutboundConnectionContext(s, endpoint, _threadContext);

            bool connectedSynchronously;

            try
            {
                connectedSynchronously = s.TryConnectNonBlocking(endpoint);
            }
            catch (ErrnoException ex)
            {
                return(new ValueTask <ConnectionContext>(Task.FromException <ConnectionContext>(ex)));
            }

            if (connectedSynchronously)
            {
                context.LocalEndPoint = s.GetLocalAddress();
                return(new ValueTask <ConnectionContext>(context));
            }

            var tcs = new TaskCompletionSource <ConnectionContext>();

            context.ConnectCompletion = tcs;

            // Socket will become writable, once connect completed
            _clientSocketQueue.Enqueue(context);
            _threadContext.Notify();

            return(new ValueTask <ConnectionContext>(tcs.Task));
        }