예제 #1
0
 private void Cleanup()
 {
     _pipeEnds.Dispose();
     foreach (var handler in _handlers)
     {
         IOInterop.Close(handler);
     }
 }
 protected unsafe PosixResult TryRead(ArraySegment <byte> buffer)
 {
     // TODO: validate buffer
     fixed(byte *buf = buffer.Array)
     {
         return(IOInterop.Read(this, buf + buffer.Offset, buffer.Count));
     }
 }
예제 #3
0
 public void Dispose()
 {
     if (Socket1 != -1)
     {
         IOInterop.Close(Socket1);
         Socket1 = -1;
     }
     if (Socket2 != -1)
     {
         IOInterop.Close(Socket2);
         Socket2 = -1;
     }
 }
예제 #4
0
        public unsafe static PosixResult AcceptAndSendHandleTo(Socket fromSocket, int toSocket)
        {
            int     acceptFd = fromSocket.DangerousGetHandle().ToInt32();
            ssize_t rv;

            do
            {
                rv = accept4(acceptFd, null, null, SOCK_CLOEXEC);
            } while (rv < 0 && errno == EINTR);

            if (rv != -1)
            {
                int acceptedFd = (int)rv;

                byte  dummyBuffer = 0;
                iovec iov         = default(iovec);
                iov.iov_base = &dummyBuffer;
                iov.iov_len  = 1;

                int   controlLength = CMSG_SPACE(sizeof(int));
                byte *control       = stackalloc byte[controlLength];

                msghdr header = default(msghdr);
                header.msg_iov        = &iov;
                header.msg_iovlen     = 1;
                header.msg_control    = control;
                header.msg_controllen = controlLength;

                cmsghdr *cmsg = CMSG_FIRSTHDR(&header);
                cmsg->cmsg_level = SOL_SOCKET;
                cmsg->cmsg_type  = SCM_RIGHTS;
                cmsg->cmsg_len   = CMSG_LEN(sizeof(int));
                int *fdptr = (int *)CMSG_DATA(cmsg);
                *    fdptr = acceptedFd;

                do
                {
                    rv = sendmsg(toSocket, &header, MSG_NOSIGNAL);
                } while (rv < 0 && errno == EINTR);

                IOInterop.Close(acceptedFd);
            }

            return(PosixResult.FromReturnValue(rv));
        }
            private int HandleAccept(TSocket tacceptSocket)
            {
                var         type     = tacceptSocket.Type;
                int         clientFd = -1;
                PosixResult result;

                if (type == SocketFlags.TypeAccept)
                {
                    // TODO: should we handle more than 1 accept? If we do, we shouldn't be to eager
                    //       as that might give the kernel the impression we have nothing to do
                    //       which could interfere with the SO_REUSEPORT load-balancing.
                    result = tacceptSocket.TryAccept(out clientFd, blocking: false);
                }
                else
                {
                    result = tacceptSocket.TryReceiveSocket(out clientFd, blocking: false);
                    if (result.Value == 0)
                    {
                        // The socket passing us file descriptors has closed.
                        // We dispose our end so we get get removed from the epoll.
                        tacceptSocket.Close();
                        return(0);
                    }
                }
                if (result.IsSuccess)
                {
                    TSocket tsocket;
                    try
                    {
                        SocketFlags flags = SocketFlags.TypeClient | (tacceptSocket.IsDeferSend ? SocketFlags.DeferSend : SocketFlags.None);
                        tsocket = new TSocket(this, clientFd, flags)
                        {
                            ZeroCopyThreshold = tacceptSocket.ZeroCopyThreshold
                        };

                        bool ipSocket = !object.ReferenceEquals(tacceptSocket.LocalAddress, NotIPSocket);

                        // Store the last LocalAddress on the tacceptSocket so we might reuse it instead
                        // of allocating a new one for the same address.
                        IPEndPointStruct localAddress  = default(IPEndPointStruct);
                        IPEndPointStruct remoteAddress = default(IPEndPointStruct);
                        if (ipSocket && tsocket.TryGetLocalIPAddress(out localAddress, tacceptSocket.LocalAddress))
                        {
                            tsocket.LocalAddress = localAddress.Address;
                            tsocket.LocalPort    = localAddress.Port;
                            if (tsocket.TryGetPeerIPAddress(out remoteAddress))
                            {
                                tsocket.RemoteAddress = remoteAddress.Address;
                                tsocket.RemotePort    = remoteAddress.Port;
                            }
                        }
                        else
                        {
                            // This is not an IP socket.
                            tacceptSocket.LocalAddress = NotIPSocket;
                            ipSocket = false;
                        }

                        if (ipSocket)
                        {
                            tsocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1);
                        }
                    }
                    catch
                    {
                        IOInterop.Close(clientFd);
                        return(0);
                    }

                    tsocket.MiddlewareTask = _connectionDispatcher.OnConnection(tsocket);

                    lock (_sockets)
                    {
                        _sockets.Add(clientFd, tsocket);
                    }

                    bool dataMayBeAvailable = tacceptSocket.IsDeferAccept;
                    tsocket.Start(dataMayBeAvailable);

                    return(1);
                }
                else
                {
                    return(0);
                }
            }
            private TSocket CreateAcceptSocket(IPEndPoint endPoint, SocketFlags flags)
            {
                int acceptSocketFd = -1;
                int port           = endPoint.Port;

                try
                {
                    bool ipv4 = endPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;
                    SocketInterop.Socket(ipv4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp, blocking: false,
                                         out acceptSocketFd).ThrowOnError();

                    TSocket acceptSocket = new TSocket(this, acceptSocketFd, flags);

                    if (!ipv4)
                    {
                        // Kestrel does mapped ipv4 by default.
                        acceptSocket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, 0);
                    }
                    if (_transportOptions.ReceiveOnIncomingCpu)
                    {
                        if (_transportThread.CpuId != -1)
                        {
                            if (!acceptSocket.TrySetSocketOption(SocketOptionLevel.Socket, SocketOptionName.IncomingCpu, _transportThread.CpuId))
                            {
                                _logger.LogWarning($"Cannot enable nameof{SocketOptionName.IncomingCpu} for {endPoint}");
                            }
                        }
                    }
                    // Linux: allow bind during linger time
                    acceptSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
                    // Linux: allow concurrent binds and let the kernel do load-balancing
                    acceptSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReusePort, 1);
                    if ((flags & SocketFlags.DeferAccept) != 0)
                    {
                        // Linux: wait up to 1 sec for data to arrive before accepting socket
                        acceptSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.DeferAccept, 1);
                    }
                    acceptSocket.ZeroCopyThreshold = LinuxTransportOptions.NoZeroCopy;
                    if (_transportOptions.ZeroCopy && _transportOptions.ZeroCopyThreshold != LinuxTransportOptions.NoZeroCopy)
                    {
                        if (acceptSocket.TrySetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ZeroCopy, 1))
                        {
                            acceptSocket.ZeroCopyThreshold = _transportOptions.ZeroCopyThreshold;
                        }
                    }

                    acceptSocket.Bind(endPoint);
                    if (port == 0)
                    {
                        // When testing we want the OS to select a free port
                        port = acceptSocket.GetLocalIPAddress().Port;
                    }

                    acceptSocket.Listen(ListenBacklog);

                    endPoint.Port = port;
                    return(acceptSocket);
                }
                catch
                {
                    if (acceptSocketFd != -1)
                    {
                        IOInterop.Close(acceptSocketFd);
                    }
                    throw;
                }
            }
            private TSocket CreateAcceptSocket(IPEndPoint endPoint, SocketFlags flags)
            {
                int acceptSocketFd = -1;
                int port           = endPoint.Port;

                try
                {
                    bool ipv4 = endPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;
                    SocketInterop.Socket(ipv4 ? AF_INET : AF_INET6, SOCK_STREAM, IPPROTO_TCP, blocking: false,
                                         out acceptSocketFd).ThrowOnError();

                    TSocket acceptSocket = new TSocket(this, acceptSocketFd, flags);

                    if (!ipv4)
                    {
                        // Kestrel does mapped ipv4 by default.
                        acceptSocket.SetSocketOption(SOL_IPV6, IPV6_V6ONLY, 0);
                    }
                    if (_transportOptions.ReceiveOnIncomingCpu)
                    {
                        if (_transportThread.CpuId != -1)
                        {
                            if (!acceptSocket.TrySetSocketOption(SOL_SOCKET, SO_INCOMING_CPU, _transportThread.CpuId))
                            {
                                _logger.LogWarning($"Cannot enable SO_INCOMING_CPU for {endPoint}");
                            }
                        }
                    }
                    // Linux: allow bind during linger time
                    acceptSocket.SetSocketOption(SOL_SOCKET, SO_REUSEADDR, 1);
                    // Linux: allow concurrent binds and let the kernel do load-balancing
                    acceptSocket.SetSocketOption(SOL_SOCKET, SO_REUSEPORT, 1);
                    if ((flags & SocketFlags.DeferAccept) != 0)
                    {
                        // Linux: wait up to 1 sec for data to arrive before accepting socket
                        acceptSocket.SetSocketOption(SOL_TCP, TCP_DEFER_ACCEPT, 1);
                    }
                    acceptSocket.ZeroCopyThreshold = LinuxTransportOptions.NoZeroCopy;
                    if (_transportOptions.ZeroCopy && _transportOptions.ZeroCopyThreshold != LinuxTransportOptions.NoZeroCopy)
                    {
                        if (acceptSocket.TrySetSocketOption(SOL_SOCKET, SO_ZEROCOPY, 1))
                        {
                            acceptSocket.ZeroCopyThreshold = _transportOptions.ZeroCopyThreshold;
                        }
                    }

                    acceptSocket.Bind(endPoint);
                    if (port == 0)
                    {
                        // When testing we want the OS to select a free port
                        port = acceptSocket.GetLocalIPAddress().Port;
                    }

                    acceptSocket.Listen(ListenBacklog);

                    endPoint.Port = port;
                    return(acceptSocket);
                }
                catch
                {
                    if (acceptSocketFd != -1)
                    {
                        IOInterop.Close(acceptSocketFd);
                    }
                    throw;
                }
            }
 protected unsafe PosixResult TryRead(byte *buffer, int length)
 {
     return(IOInterop.Read(this, buffer, length));
 }
        protected override bool ReleaseHandle()
        {
            var result = IOInterop.Close(handle.ToInt32());

            return(result.IsSuccess);
        }
예제 #10
0
            private int HandleAccept(TSocket tacceptSocket)
            {
                var         type     = tacceptSocket.Type;
                int         clientFd = -1;
                PosixResult result;

                if (type == SocketFlags.TypeAccept)
                {
                    // TODO: should we handle more than 1 accept? If we do, we shouldn't be to eager
                    //       as that might give the kernel the impression we have nothing to do
                    //       which could interfere with the SO_REUSEPORT load-balancing.
                    result = tacceptSocket.TryAccept(out clientFd, blocking: false);
                }
                else
                {
                    result = tacceptSocket.TryReceiveSocket(out clientFd, blocking: false);
                    if (result.Value == 0)
                    {
                        // The socket passing us file descriptors has closed.
                        // We dispose our end so we get get removed from the epoll.
                        tacceptSocket.Close();
                        return(0);
                    }
                }
                if (result.IsSuccess)
                {
                    TSocket tsocket;
                    try
                    {
                        SocketFlags flags = SocketFlags.TypeClient | (tacceptSocket.IsDeferSend ? SocketFlags.DeferSend : SocketFlags.None);
                        tsocket = new TSocket(this, clientFd, flags, _transportOptions)
                        {
                            ZeroCopyThreshold = tacceptSocket.ZeroCopyThreshold
                        };

                        var  localIpEndPoint = tacceptSocket.LocalEndPoint as IPEndPoint;
                        bool ipSocket        = !object.ReferenceEquals(localIpEndPoint?.Address, NotIPSocket);

                        // Store the last LocalAddress on the tacceptSocket so we might reuse it instead
                        // of allocating a new one for the same address.
                        IPEndPointStruct localAddress  = default(IPEndPointStruct);
                        IPEndPointStruct remoteAddress = default(IPEndPointStruct);
                        if (ipSocket && tsocket.TryGetLocalIPAddress(out localAddress, localIpEndPoint?.Address))
                        {
                            tsocket.LocalEndPoint = new IPEndPoint(localAddress.Address, localAddress.Port);

                            if (tsocket.TryGetPeerIPAddress(out remoteAddress))
                            {
                                tsocket.RemoteEndPoint = new IPEndPoint(remoteAddress.Address, remoteAddress.Port);
                            }
                        }
                        else
                        {
                            // This is not an IP socket.
                            // REVIEW: Should LocalEndPoint be null instead? Some other EndPoint type?
                            tacceptSocket.LocalEndPoint = new IPEndPoint(NotIPSocket, 0);
                            ipSocket = false;
                        }

                        if (ipSocket)
                        {
                            tsocket.SetSocketOption(SOL_TCP, TCP_NODELAY, 1);
                        }
                    }
                    catch
                    {
                        IOInterop.Close(clientFd);
                        return(0);
                    }

                    bool accepted = _acceptQueue.Writer.TryWrite(tsocket);
                    Debug.Assert(accepted, "The connection was not written to the channel!");

                    lock (_sockets)
                    {
                        _sockets.Add(clientFd, tsocket);
                    }

                    bool dataMayBeAvailable = tacceptSocket.IsDeferAccept;
                    tsocket.Start(dataMayBeAvailable);

                    return(1);
                }
                else
                {
                    return(0);
                }
            }