/// <summary>
 /// Delete target peer for socket.
 /// </summary>
 /// <param name="socket">The socket to set.</param>
 /// <param name="peer_address">Peer address.</param>
 /// <param name="throw_on_error">True to throw on error.</param>
 /// <returns>The NT status code.</returns>
 public static NtStatus DeletePeerTargetName(this Socket socket, IPEndPoint peer_address, bool throw_on_error)
 {
     byte[] addr = peer_address.ToArray();
     return(SocketNativeMethods.WSADeleteSocketPeerTargetName(
                socket.Handle, addr, addr.Length, IntPtr.Zero,
                IntPtr.Zero).GetNtStatus(throw_on_error));
 }
        /// <summary>
        /// Query the socket security information.
        /// </summary>
        /// <param name="socket">The socket to query.</param>
        /// <param name="peer_address">Optional peer address. Only needed for datagram sockets.</param>
        /// <param name="desired_access">Optional desired access for peer tokens. If set to None then no tokens will be returned.</param>
        /// <param name="throw_on_error">True to throw on error.</param>
        /// <returns>The socket security information.</returns>
        public static NtResult <SocketSecurityInformation> QuerySecurity(this Socket socket, IPEndPoint peer_address,
                                                                         TokenAccessRights desired_access, bool throw_on_error)
        {
            var query = new SOCKET_SECURITY_QUERY_TEMPLATE_IPSEC2
            {
                SecurityProtocol    = SOCKET_SECURITY_PROTOCOL.IPsec2,
                PeerAddress         = peer_address.ToSocketStorage(),
                PeerTokenAccessMask = desired_access,
                FieldMask           = SocketSecurityQueryFieldMask.MmSaId | SocketSecurityQueryFieldMask.QmSaId
            };

            using (var template = query.ToBuffer())
            {
                int length = 0;
                SocketNativeMethods.WSAQuerySocketSecurity(socket.Handle, template, template.Length,
                                                           SafeHGlobalBuffer.Null, ref length, IntPtr.Zero, IntPtr.Zero);
                Win32Error error = SocketNativeMethods.WSAGetLastError();
                if (error != Win32Error.WSAEMSGSIZE)
                {
                    return(error.CreateResultFromDosError <SocketSecurityInformation>(throw_on_error));
                }
                using (var buffer = new SafeStructureInOutBuffer <SOCKET_SECURITY_QUERY_INFO>(length, false))
                {
                    return(SocketNativeMethods.WSAQuerySocketSecurity(socket.Handle, template, template.Length,
                                                                      buffer, ref length, IntPtr.Zero, IntPtr.Zero).CreateWSAResult(throw_on_error,
                                                                                                                                    () => new SocketSecurityInformation(buffer)));
                }
            }
        }
 private static NtResult <T> CreateWSAResult <T>(this int error, bool throw_on_error, Func <T> create_func)
 {
     if (error >= 0)
     {
         return(create_func().CreateResult());
     }
     return(SocketNativeMethods.WSAGetLastError().CreateResultFromDosError <T>(throw_on_error));
 }
 private static NtStatus GetNtStatus(this int error, bool throw_on_error)
 {
     if (error >= 0)
     {
         return(NtStatus.STATUS_SUCCESS);
     }
     return(SocketNativeMethods.WSAGetLastError().ToNtException(throw_on_error));
 }
 /// <summary>
 /// Set the socket security information.
 /// </summary>
 /// <param name="socket">The socket to set.</param>
 /// <param name="settings">The security settings.</param>
 /// <param name="throw_on_error">True to throw on error.</param>
 /// <returns>The NT status code.</returns>
 public static NtStatus SetSecurity(this Socket socket, SocketSecuritySettings settings, bool throw_on_error)
 {
     using (var buffer = settings?.ToBuffer() ?? SafeHGlobalBuffer.Null)
     {
         return(SocketNativeMethods.WSASetSocketSecurity(socket.Handle, buffer,
                                                         buffer.Length, IntPtr.Zero, IntPtr.Zero).GetNtStatus(throw_on_error));
     }
 }
        /// <summary>
        /// Set target peer for socket.
        /// </summary>
        /// <param name="socket">The socket to set.</param>
        /// <param name="target_name">The target name.</param>
        /// <param name="peer_address">Optional peer address. Only needed for datagram sockets.</param>
        /// <param name="throw_on_error">True to throw on error.</param>
        /// <returns>The NT status code.</returns>
        public static NtStatus SetPeerTargetName(this Socket socket, string target_name, IPEndPoint peer_address, bool throw_on_error)
        {
            byte[] target_name_bytes  = Encoding.Unicode.GetBytes(target_name);
            int    target_name_length = target_name_bytes.Length;
            int    total_length       = Marshal.SizeOf(typeof(SOCKET_PEER_TARGET_NAME)) + target_name_bytes.Length;

            using (var buffer = new SOCKET_PEER_TARGET_NAME()
            {
                SecurityProtocol = SOCKET_SECURITY_PROTOCOL.IPsec2,
                PeerAddress = peer_address.ToSocketStorage(),
                PeerTargetNameStringLen = target_name_length
            }.ToBuffer(total_length, false))
            {
                buffer.Data.WriteBytes(target_name_bytes);
                return(SocketNativeMethods.WSASetSocketPeerTargetName(
                           socket.Handle, buffer, buffer.Length, IntPtr.Zero,
                           IntPtr.Zero).GetNtStatus(throw_on_error));
            }
        }
 /// <summary>
 /// Impersonate the socket's peer.
 /// </summary>
 /// <param name="socket">The socket to impersonate.</param>
 /// <param name="peer_address">Optional peer address. Only needed for datagram sockets.</param>
 /// <param name="throw_on_error">True to throw on error.</param>
 /// <returns>The impersonation context.</returns>
 public static NtResult <ThreadImpersonationContext> Impersonate(this Socket socket, IPEndPoint peer_address, bool throw_on_error)
 {
     byte[] addr = peer_address?.ToArray();
     return(SocketNativeMethods.WSAImpersonateSocketPeer(socket.Handle, addr, addr?.Length ?? 0)
            .CreateWSAResult(throw_on_error, () => new ThreadImpersonationContext()));
 }