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 ? 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;
                }
            }
            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;
                }
            }
Пример #4
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);
                }
            }