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; } }