예제 #1
0
        private static unsafe bool ToIPEndPointStruct(sockaddr_storage *addr, out IPEndPointStruct ep, IPAddress reuseAddress = null)
        {
            if (addr->ss_family == AF_INET)
            {
                sockaddr_in *addrIn = (sockaddr_in *)addr;
                long         value  = ((addrIn->sin_addr.s_addr[3] << 24 | addrIn->sin_addr.s_addr[2] << 16 | addrIn->sin_addr.s_addr[1] << 8 | addrIn->sin_addr.s_addr[0]) & 0x0FFFFFFFF);
#pragma warning disable CS0618 // 'IPAddress.Address' is obsolete
                bool matchesReuseAddress = reuseAddress != null && reuseAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && reuseAddress.Address == value;
#pragma warning restore CS0618
                int port = ntohs(addrIn->sin_port);
                ep = new IPEndPointStruct(matchesReuseAddress ? reuseAddress : new IPAddress(value), port);
                return(true);
            }
            else if (addr->ss_family == AF_INET6)
            {
                sockaddr_in6 *addrIn = (sockaddr_in6 *)addr;
                // We can't check if we can use reuseAddress without allocating.
                const int length = 16;
                var       bytes  = new byte[length];
                for (int i = 0; i < length; i++)
                {
                    bytes[i] = addrIn->sin6_addr.s6_addr[i];
                }
                int port = ntohs(addrIn->sin6_port);
                ep = new IPEndPointStruct(new IPAddress(bytes, addrIn->sin6_scope_id), port);
                return(true);
            }
            else
            {
                ep = default(IPEndPointStruct);
                return(false);
            }
        }
예제 #2
0
 internal static unsafe void GetSockaddrInet(IPEndPointStruct inetAddress, sockaddr_storage *addr, out int length)
 {
     if (inetAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
     {
         sockaddr_in *addrIn = (sockaddr_in *)addr;
         addrIn->sin_family = AF_INET;
         addrIn->sin_port   = htons((ushort)inetAddress.Port);
         int bytesWritten;
         inetAddress.Address.TryWriteBytes(new Span <byte>(addrIn->sin_addr.s_addr, 4), out bytesWritten);
         length = SizeOf.sockaddr_in;
     }
     else if (inetAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
     {
         sockaddr_in6 *addrIn = (sockaddr_in6 *)addr;
         addrIn->sin6_family   = AF_INET6;
         addrIn->sin6_port     = htons((ushort)inetAddress.Port);
         addrIn->sin6_flowinfo = 0;
         addrIn->sin6_scope_id = 0;
         int bytesWritten;
         inetAddress.Address.TryWriteBytes(new Span <byte>(addrIn->sin6_addr.s6_addr, 16), out bytesWritten);
         length = SizeOf.sockaddr_in6;
     }
     else
     {
         length = 0;
     }
 }
예제 #3
0
        public unsafe PosixResult TryBind(IPEndPointStruct endpoint)
        {
            sockaddr_storage addr;

            GetSockaddrInet(endpoint, &addr, out int length);

            int rv = bind(DangerousGetHandle().ToInt32(), (sockaddr *)&addr, length);

            return(PosixResult.FromReturnValue(rv));
        }
예제 #4
0
        public unsafe PosixResult TryConnect(IPEndPointStruct endpoint)
        {
            sockaddr_storage addr;

            GetSockaddrInet(endpoint, &addr, out int length);
            int rv;

            do
            {
                rv = connect(DangerousGetHandle().ToInt32(), (sockaddr *)&addr, length);
            } while (rv < 0 && errno == EINTR);

            return(PosixResult.FromReturnValue(rv));
        }
예제 #5
0
        public unsafe PosixResult TryGetPeerIPAddress(out IPEndPointStruct ep)
        {
            IPSocketAddress socketAddress;
            var             rv = SocketInterop.GetPeerName(this, (byte *)&socketAddress, sizeof(IPSocketAddress));

            if (rv.IsSuccess)
            {
                ep = socketAddress.ToIPEndPoint();
            }
            else
            {
                ep = default(IPEndPointStruct);
            }
            return(rv);
        }
        public unsafe IPSocketAddress(IPEndPointStruct endPoint)
        {
            bool ipv4 = endPoint.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork;

            FlowInfo = 0;
            _family  = (short)(ipv4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6);
            ScopeId  = ipv4 ? 0 : (uint)endPoint.Address.ScopeId;
            Port     = (ushort)endPoint.Port;
            var bytes = endPoint.Address.GetAddressBytes();

            fixed(byte *address = Address)
            {
                for (int i = 0; i < (ipv4 ? 4 : 16); i++)
                {
                    address[i] = bytes[i];
                }
            }
        }
예제 #7
0
        public static unsafe PosixResult TryGetPeerIPAddress(int socket, out IPEndPointStruct ep, IPAddress reuseAddress = null)
        {
            sockaddr_storage socketAddress;
            var rv = SocketInterop.GetPeerName(socket, &socketAddress);

            if (rv.IsSuccess)
            {
                if (!ToIPEndPointStruct(&socketAddress, out ep, reuseAddress))
                {
                    return(new PosixResult(PosixResult.EINVAL));
                }
            }
            else
            {
                ep = default(IPEndPointStruct);
            }
            return(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);
                }
            }
예제 #9
0
 public unsafe PosixResult TryGetPeerIPAddress(out IPEndPointStruct ep)
 => SocketInterop.TryGetPeerIPAddress(this, out ep);
예제 #10
0
 public unsafe PosixResult TryGetLocalIPAddress(out IPEndPointStruct ep, IPAddress reuseAddress = null)
 => SocketInterop.TryGetLocalIPAddress(this, out ep, reuseAddress);
예제 #11
0
 public void Connect(IPEndPointStruct endpoint)
 {
     TryConnect(endpoint)
     .ThrowOnError();
 }
예제 #12
0
 public void Bind(IPEndPointStruct endpoint)
 {
     TryBind(endpoint)
     .ThrowOnError();
 }
예제 #13
0
 public static unsafe PosixResult TryGetPeerIPAddress(Socket socket, out IPEndPointStruct ep, IPAddress reuseAddress = null)
 => TryGetPeerIPAddress(socket.DangerousGetHandle().ToInt32(), out ep, reuseAddress);
예제 #14
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);
                }
            }
예제 #15
0
        public unsafe PosixResult TryConnect(IPEndPointStruct endpoint)
        {
            IPSocketAddress socketAddress = new IPSocketAddress(endpoint);

            return(SocketInterop.Connect(this, (byte *)&socketAddress, sizeof(IPSocketAddress)));
        }