SspiHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / IdentityModel / System / IdentityModel / SspiHelper.cs / 1305376 / SspiHelper.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.IdentityModel 
{
    using System.Runtime.InteropServices; 
    using System.Security.Authentication.ExtendedProtection; 
    using System.Security.Cryptography.X509Certificates;
 
    internal enum CredentialUse
    {
        Inbound             = 0x1,
        Outbound            = 0x2, 
        Both                = 0x3,
    } 
 
    internal enum Endianness
    { 
        Network             = 0x00,
        Native              = 0x10,
    }
 
    internal  enum    CertificateEncoding
    { 
        Zero                     = 0, 
        X509AsnEncoding          = unchecked((int) 0x00000001),
        X509NdrEncoding          = unchecked((int) 0x00000002), 
        Pkcs7AsnEncoding         = unchecked((int) 0x00010000),
        Pkcs7NdrEncoding         = unchecked((int) 0x00020000),
        AnyAsnEncoding           = X509AsnEncoding | Pkcs7AsnEncoding
    } 

    internal enum BufferType 
    { 
        Empty               = 0x00,
        Data                = 0x01, 
        Token               = 0x02,
        Parameters          = 0x03,
        Missing             = 0x04,
        Extra               = 0x05, 
        Trailer             = 0x06,
        Header              = 0x07, 
        Padding             = 0x09, 
        Stream              = 0x0A,
        ChannelBindings = 0x0E, 
    }

    internal enum SecurityStatus
    { 
        OK                  = 0x00000000,
        OutOfMemory         = unchecked((int) 0x80090300), 
        InvalidHandle       = unchecked((int) 0x80090301), 
        Unsupported         = unchecked((int) 0x80090302),
        TargetUnknown       = unchecked((int) 0x80090303), 
        InternalError       = unchecked((int) 0x80090304),
        PackageNotFound     = unchecked((int) 0x80090305),
        NotOwner            = unchecked((int) 0x80090306),
        CannotInstall       = unchecked((int) 0x80090307), 
        InvalidToken        = unchecked((int) 0x80090308),
        LogonDenied         = unchecked((int) 0x8009030C), 
        UnknownCredential   = unchecked((int) 0x8009030D), 
        NoCredentials       = unchecked((int) 0x8009030E),
        MessageAltered      = unchecked((int) 0x8009030F), 

        ContinueNeeded      = unchecked((int) 0x00090312),
        CompleteNeeded      = unchecked((int) 0x00090313),
        CompAndContinue     = unchecked((int) 0x00090314), 
        ContextExpired      = unchecked((int) 0x00090317),
        IncompleteMessage   = unchecked((int) 0x80090318), 
        IncompleteCred      = unchecked((int) 0x80090320), 
        BufferNotEnough     = unchecked((int) 0x80090321),
        WrongPrincipal      = unchecked((int) 0x80090322), 
        UntrustedRoot       = unchecked((int) 0x80090325),
        UnknownCertificate  = unchecked((int) 0x80090327),

        CredentialsNeeded   = unchecked((int) 0x00090320), 
        Renegotiate         = unchecked((int) 0x00090321),
    } 
 
    internal enum ContextAttribute
    { 
        //
        // look into  and 
        //
        Sizes               = 0x00, 
        Names               = 0x01,
        Lifespan            = 0x02, 
        DceInfo             = 0x03, 
        StreamSizes         = 0x04,
        //KeyInfo             = 0x05, must not be used, see ConnectionInfo instead 
        Authority           = 0x06,
        // SECPKG_ATTR_PROTO_INFO          = 7,
        // SECPKG_ATTR_PASSWORD_EXPIRY     = 8,
        SessionKey          = 0x09, 
        PackageInfo         = 0x0A,
        // SECPKG_ATTR_USER_FLAGS          = 11, 
        NegotiationInfo    = 0x0C, 
        // SECPKG_ATTR_NATIVE_NAMES        = 13,
        // SECPKG_ATTR_FLAGS               = 14, 
        Flags              = 0x0E,
        // SECPKG_ATTR_USE_VALIDATED       = 15,
        // SECPKG_ATTR_CREDENTIAL_NAME     = 16,
        // SECPKG_ATTR_TARGET_INFORMATION  = 17, 
        // SECPKG_ATTR_ACCESS_TOKEN        = 18,
        // SECPKG_ATTR_TARGET              = 19, 
        // SECPKG_ATTR_AUTHENTICATION_ID   = 20, 
        // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET 27
        SpecifiedTarget     = 0x1B, 
        RemoteCertificate   = 0x53,
        LocalCertificate    = 0x54,
        RootStore           = 0x55,
        IssuerListInfoEx    = 0x59, 
        ConnectionInfo      = 0x5A,
        EapKey              = 0x5B 
    } 

    internal enum CredentialStatus 
    {
        InValidParameter = unchecked((int)0x57),
        NoSuchPackage = unchecked((int)0x554),
        NotSupported = unchecked((int)0x32), 
        Cancelled = unchecked((int)0x4C7),
        Success = unchecked((int)0x0), 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal unsafe struct SecurityBufferStruct
    {
        public int          count;
        public BufferType   type; 
        public IntPtr       token;
 
        public static readonly int Size = sizeof(SecurityBufferStruct); 
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    internal struct AuthIdentityEx
    {
        // see SEC_WINNT_AUTH_IDENTITY_EX 
        internal int Version;
 
        internal int Length; 

        internal string UserName; 

        internal int UserNameLength;

        internal string Domain; 

        internal int DomainLength; 
 
        internal string Password;
 
        internal int PasswordLength;

        internal int Flags;
 
        internal string PackageList;
 
        internal int PackageListLength; 

        // sspi.h: #define SEC_WINNT_AUTH_IDENTITY_VERSION 0x200 
        static readonly int WinNTAuthIdentityVersion = 0x200;

        internal AuthIdentityEx(string userName, string password, string domain, params string[] additionalPackages)
        { 
            Version = WinNTAuthIdentityVersion;
            Length = Marshal.SizeOf(typeof(AuthIdentityEx)); 
            UserName = userName; 
            UserNameLength = userName == null ? 0 : userName.Length;
            Password = password; 
            PasswordLength = password == null ? 0 : password.Length;
            Domain = domain;
            DomainLength = domain == null ? 0 : domain.Length;
 
            // Flags are 2 for Unicode and 1 for ANSI. We use 2 on NT
            Flags = 2; 
 
            if (null == additionalPackages)
            { 
                PackageList = null;
                PackageListLength = 0;
            }
            else 
            {
                PackageList = String.Join(",", additionalPackages); 
                PackageListLength = PackageList.Length; 
            }
        } 
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SecureCredential 
    {
        /* 
        typedef struct _SCHANNEL_CRED 
        {
            DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION 
            DWORD           cCreds;
            PCCERT_CONTEXT *paCred;
            HCERTSTORE      hRootStore;
 
            DWORD           cMappers;
            struct _HMAPPER **aphMappers; 
 
            DWORD           cSupportedAlgs;
            ALG_ID *        palgSupportedAlgs; 

            DWORD           grbitEnabledProtocols;
            DWORD           dwMinimumCipherStrength;
            DWORD           dwMaximumCipherStrength; 
            DWORD           dwSessionLifespan;
            DWORD           dwFlags; 
            DWORD           reserved; 
        } SCHANNEL_CRED, *PSCHANNEL_CRED;
        */ 
        public const int CurrentVersion = 0x4;

        public int version;
        public int cCreds; 

        // ptr to an array of pointers 
        // Cannot convert it to SafeHandle because it gets wrapped with another pointer 
        // right before native AcquireCredentialsHandle call
        public IntPtr certContextArray; 

        private IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE
        public int cMappers;
        private IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE 
        public int cSupportedAlgs;
        private IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE 
        public SchProtocols grbitEnabledProtocols; 
        public int dwMinimumCipherStrength;
        public int dwMaximumCipherStrength; 
        public int dwSessionLifespan;
        public SecureCredential.Flags dwFlags;
        public int reserved;
 
        [Flags]
        public enum Flags 
        { 
            Zero            = 0,
            NoSystemMapper  = 0x02, 
            NoNameCheck     = 0x04,
            ValidateManual  = 0x08,
            NoDefaultCred   = 0x10,
            ValidateAuto    = 0x20 
        }
 
        public SecureCredential(int version, X509Certificate2 certificate, 
            SecureCredential.Flags flags, SchProtocols protocols)
        { 
            //Setting default values
            rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
            cCreds = cMappers = cSupportedAlgs = 0;
            dwMinimumCipherStrength = dwMaximumCipherStrength = 0; 
            dwSessionLifespan = reserved = 0;
 
            this.version = version; 
            dwFlags = flags;
            grbitEnabledProtocols = protocols; 
            if (certificate != null)
            {
                certContextArray = certificate.Handle;
                cCreds = 1; 
            }
        } 
    } // SecureCredential 

    static class IntPtrHelper 
    {
        private const string KERNEL32 = "kernel32.dll";

        //internal static bool IsZero(IntPtr a) 
        //{
        //    return ((long) a)==0; 
        //} 

        //internal static IntPtr Add(IntPtr a, IntPtr b) 
        //{
        //    return (IntPtr) ((long) a + (long) b);
        //}
 
        //internal static IntPtr Add(IntPtr a, long b)
        //{ 
        //    return (IntPtr) ((long) a + b); 
        //}
 
        //internal static IntPtr Add(long a, IntPtr b)
        //{
        //    return (IntPtr) (a + (long) b);
        //} 

        internal static IntPtr Add(IntPtr a, int b) 
        { 
            return (IntPtr) ((long) a + (long) b);
        } 

        //internal static IntPtr Add(int a, IntPtr b)
        //{
        //    return (IntPtr) ((long) a + (long) b); 
        //}
    } 
 
    [StructLayout(LayoutKind.Sequential)]
    internal unsafe class SecurityBufferDescriptor 
    {
        /*
        typedef struct _SecBufferDesc {
            ULONG        ulVersion; 
            ULONG        cBuffers;
            PSecBuffer   pBuffers; 
        } SecBufferDesc, * PSecBufferDesc; 
        */
        public  readonly    int     Version; 
        public  readonly    int     Count;
        public  void * UnmanagedPointer;

        public SecurityBufferDescriptor(int count) 
        {
            Version = 0; 
            Count = count; 
            UnmanagedPointer = null;
        } 
    } // SecurityBufferDescriptor

    internal class SecurityBuffer
    { 
        /*
        typedef struct _SecBuffer { 
            ULONG        cbBuffer; 
            ULONG        BufferType;
            PVOID        pvBuffer; 
        } SecBuffer, *PSecBuffer;
        */
        public int size;
        public BufferType type; 
        public byte[] token;
        public int offset; 
        public SafeHandle unmanagedToken; 

        public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) 
        {
            this.offset = offset;
            this.size = (data == null) ? 0 : size;
            this.type = tokentype; 
            this.token = data;
        } 
 
        public SecurityBuffer(byte[] data, BufferType tokentype)
        { 
            this.size = (data == null) ? 0 : data.Length;
            this.type = tokentype;
            this.token = data;
        } 

        public SecurityBuffer(int size, BufferType tokentype) 
        { 
            this.size = size;
            this.type = tokentype; 
            this.token = size == 0 ? null : DiagnosticUtility.Utility.AllocateByteArray(size);
        }

        public SecurityBuffer( ChannelBinding channelBinding ) 
        {
            this.size = channelBinding.Size; 
            this.type = BufferType.ChannelBindings; 
            this.unmanagedToken = channelBinding;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.IdentityModel 
{
    using System.Runtime.InteropServices; 
    using System.Security.Authentication.ExtendedProtection; 
    using System.Security.Cryptography.X509Certificates;
 
    internal enum CredentialUse
    {
        Inbound             = 0x1,
        Outbound            = 0x2, 
        Both                = 0x3,
    } 
 
    internal enum Endianness
    { 
        Network             = 0x00,
        Native              = 0x10,
    }
 
    internal  enum    CertificateEncoding
    { 
        Zero                     = 0, 
        X509AsnEncoding          = unchecked((int) 0x00000001),
        X509NdrEncoding          = unchecked((int) 0x00000002), 
        Pkcs7AsnEncoding         = unchecked((int) 0x00010000),
        Pkcs7NdrEncoding         = unchecked((int) 0x00020000),
        AnyAsnEncoding           = X509AsnEncoding | Pkcs7AsnEncoding
    } 

    internal enum BufferType 
    { 
        Empty               = 0x00,
        Data                = 0x01, 
        Token               = 0x02,
        Parameters          = 0x03,
        Missing             = 0x04,
        Extra               = 0x05, 
        Trailer             = 0x06,
        Header              = 0x07, 
        Padding             = 0x09, 
        Stream              = 0x0A,
        ChannelBindings = 0x0E, 
    }

    internal enum SecurityStatus
    { 
        OK                  = 0x00000000,
        OutOfMemory         = unchecked((int) 0x80090300), 
        InvalidHandle       = unchecked((int) 0x80090301), 
        Unsupported         = unchecked((int) 0x80090302),
        TargetUnknown       = unchecked((int) 0x80090303), 
        InternalError       = unchecked((int) 0x80090304),
        PackageNotFound     = unchecked((int) 0x80090305),
        NotOwner            = unchecked((int) 0x80090306),
        CannotInstall       = unchecked((int) 0x80090307), 
        InvalidToken        = unchecked((int) 0x80090308),
        LogonDenied         = unchecked((int) 0x8009030C), 
        UnknownCredential   = unchecked((int) 0x8009030D), 
        NoCredentials       = unchecked((int) 0x8009030E),
        MessageAltered      = unchecked((int) 0x8009030F), 

        ContinueNeeded      = unchecked((int) 0x00090312),
        CompleteNeeded      = unchecked((int) 0x00090313),
        CompAndContinue     = unchecked((int) 0x00090314), 
        ContextExpired      = unchecked((int) 0x00090317),
        IncompleteMessage   = unchecked((int) 0x80090318), 
        IncompleteCred      = unchecked((int) 0x80090320), 
        BufferNotEnough     = unchecked((int) 0x80090321),
        WrongPrincipal      = unchecked((int) 0x80090322), 
        UntrustedRoot       = unchecked((int) 0x80090325),
        UnknownCertificate  = unchecked((int) 0x80090327),

        CredentialsNeeded   = unchecked((int) 0x00090320), 
        Renegotiate         = unchecked((int) 0x00090321),
    } 
 
    internal enum ContextAttribute
    { 
        //
        // look into  and 
        //
        Sizes               = 0x00, 
        Names               = 0x01,
        Lifespan            = 0x02, 
        DceInfo             = 0x03, 
        StreamSizes         = 0x04,
        //KeyInfo             = 0x05, must not be used, see ConnectionInfo instead 
        Authority           = 0x06,
        // SECPKG_ATTR_PROTO_INFO          = 7,
        // SECPKG_ATTR_PASSWORD_EXPIRY     = 8,
        SessionKey          = 0x09, 
        PackageInfo         = 0x0A,
        // SECPKG_ATTR_USER_FLAGS          = 11, 
        NegotiationInfo    = 0x0C, 
        // SECPKG_ATTR_NATIVE_NAMES        = 13,
        // SECPKG_ATTR_FLAGS               = 14, 
        Flags              = 0x0E,
        // SECPKG_ATTR_USE_VALIDATED       = 15,
        // SECPKG_ATTR_CREDENTIAL_NAME     = 16,
        // SECPKG_ATTR_TARGET_INFORMATION  = 17, 
        // SECPKG_ATTR_ACCESS_TOKEN        = 18,
        // SECPKG_ATTR_TARGET              = 19, 
        // SECPKG_ATTR_AUTHENTICATION_ID   = 20, 
        // SECPKG_ATTR_CLIENT_SPECIFIED_TARGET 27
        SpecifiedTarget     = 0x1B, 
        RemoteCertificate   = 0x53,
        LocalCertificate    = 0x54,
        RootStore           = 0x55,
        IssuerListInfoEx    = 0x59, 
        ConnectionInfo      = 0x5A,
        EapKey              = 0x5B 
    } 

    internal enum CredentialStatus 
    {
        InValidParameter = unchecked((int)0x57),
        NoSuchPackage = unchecked((int)0x554),
        NotSupported = unchecked((int)0x32), 
        Cancelled = unchecked((int)0x4C7),
        Success = unchecked((int)0x0), 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal unsafe struct SecurityBufferStruct
    {
        public int          count;
        public BufferType   type; 
        public IntPtr       token;
 
        public static readonly int Size = sizeof(SecurityBufferStruct); 
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    internal struct AuthIdentityEx
    {
        // see SEC_WINNT_AUTH_IDENTITY_EX 
        internal int Version;
 
        internal int Length; 

        internal string UserName; 

        internal int UserNameLength;

        internal string Domain; 

        internal int DomainLength; 
 
        internal string Password;
 
        internal int PasswordLength;

        internal int Flags;
 
        internal string PackageList;
 
        internal int PackageListLength; 

        // sspi.h: #define SEC_WINNT_AUTH_IDENTITY_VERSION 0x200 
        static readonly int WinNTAuthIdentityVersion = 0x200;

        internal AuthIdentityEx(string userName, string password, string domain, params string[] additionalPackages)
        { 
            Version = WinNTAuthIdentityVersion;
            Length = Marshal.SizeOf(typeof(AuthIdentityEx)); 
            UserName = userName; 
            UserNameLength = userName == null ? 0 : userName.Length;
            Password = password; 
            PasswordLength = password == null ? 0 : password.Length;
            Domain = domain;
            DomainLength = domain == null ? 0 : domain.Length;
 
            // Flags are 2 for Unicode and 1 for ANSI. We use 2 on NT
            Flags = 2; 
 
            if (null == additionalPackages)
            { 
                PackageList = null;
                PackageListLength = 0;
            }
            else 
            {
                PackageList = String.Join(",", additionalPackages); 
                PackageListLength = PackageList.Length; 
            }
        } 
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct SecureCredential 
    {
        /* 
        typedef struct _SCHANNEL_CRED 
        {
            DWORD           dwVersion;      // always SCHANNEL_CRED_VERSION 
            DWORD           cCreds;
            PCCERT_CONTEXT *paCred;
            HCERTSTORE      hRootStore;
 
            DWORD           cMappers;
            struct _HMAPPER **aphMappers; 
 
            DWORD           cSupportedAlgs;
            ALG_ID *        palgSupportedAlgs; 

            DWORD           grbitEnabledProtocols;
            DWORD           dwMinimumCipherStrength;
            DWORD           dwMaximumCipherStrength; 
            DWORD           dwSessionLifespan;
            DWORD           dwFlags; 
            DWORD           reserved; 
        } SCHANNEL_CRED, *PSCHANNEL_CRED;
        */ 
        public const int CurrentVersion = 0x4;

        public int version;
        public int cCreds; 

        // ptr to an array of pointers 
        // Cannot convert it to SafeHandle because it gets wrapped with another pointer 
        // right before native AcquireCredentialsHandle call
        public IntPtr certContextArray; 

        private IntPtr rootStore; // == always null, OTHERWISE NOT RELIABLE
        public int cMappers;
        private IntPtr phMappers; // == always null, OTHERWISE NOT RELIABLE 
        public int cSupportedAlgs;
        private IntPtr palgSupportedAlgs; // == always null, OTHERWISE NOT RELIABLE 
        public SchProtocols grbitEnabledProtocols; 
        public int dwMinimumCipherStrength;
        public int dwMaximumCipherStrength; 
        public int dwSessionLifespan;
        public SecureCredential.Flags dwFlags;
        public int reserved;
 
        [Flags]
        public enum Flags 
        { 
            Zero            = 0,
            NoSystemMapper  = 0x02, 
            NoNameCheck     = 0x04,
            ValidateManual  = 0x08,
            NoDefaultCred   = 0x10,
            ValidateAuto    = 0x20 
        }
 
        public SecureCredential(int version, X509Certificate2 certificate, 
            SecureCredential.Flags flags, SchProtocols protocols)
        { 
            //Setting default values
            rootStore = phMappers = palgSupportedAlgs = certContextArray = IntPtr.Zero;
            cCreds = cMappers = cSupportedAlgs = 0;
            dwMinimumCipherStrength = dwMaximumCipherStrength = 0; 
            dwSessionLifespan = reserved = 0;
 
            this.version = version; 
            dwFlags = flags;
            grbitEnabledProtocols = protocols; 
            if (certificate != null)
            {
                certContextArray = certificate.Handle;
                cCreds = 1; 
            }
        } 
    } // SecureCredential 

    static class IntPtrHelper 
    {
        private const string KERNEL32 = "kernel32.dll";

        //internal static bool IsZero(IntPtr a) 
        //{
        //    return ((long) a)==0; 
        //} 

        //internal static IntPtr Add(IntPtr a, IntPtr b) 
        //{
        //    return (IntPtr) ((long) a + (long) b);
        //}
 
        //internal static IntPtr Add(IntPtr a, long b)
        //{ 
        //    return (IntPtr) ((long) a + b); 
        //}
 
        //internal static IntPtr Add(long a, IntPtr b)
        //{
        //    return (IntPtr) (a + (long) b);
        //} 

        internal static IntPtr Add(IntPtr a, int b) 
        { 
            return (IntPtr) ((long) a + (long) b);
        } 

        //internal static IntPtr Add(int a, IntPtr b)
        //{
        //    return (IntPtr) ((long) a + (long) b); 
        //}
    } 
 
    [StructLayout(LayoutKind.Sequential)]
    internal unsafe class SecurityBufferDescriptor 
    {
        /*
        typedef struct _SecBufferDesc {
            ULONG        ulVersion; 
            ULONG        cBuffers;
            PSecBuffer   pBuffers; 
        } SecBufferDesc, * PSecBufferDesc; 
        */
        public  readonly    int     Version; 
        public  readonly    int     Count;
        public  void * UnmanagedPointer;

        public SecurityBufferDescriptor(int count) 
        {
            Version = 0; 
            Count = count; 
            UnmanagedPointer = null;
        } 
    } // SecurityBufferDescriptor

    internal class SecurityBuffer
    { 
        /*
        typedef struct _SecBuffer { 
            ULONG        cbBuffer; 
            ULONG        BufferType;
            PVOID        pvBuffer; 
        } SecBuffer, *PSecBuffer;
        */
        public int size;
        public BufferType type; 
        public byte[] token;
        public int offset; 
        public SafeHandle unmanagedToken; 

        public SecurityBuffer(byte[] data, int offset, int size, BufferType tokentype) 
        {
            this.offset = offset;
            this.size = (data == null) ? 0 : size;
            this.type = tokentype; 
            this.token = data;
        } 
 
        public SecurityBuffer(byte[] data, BufferType tokentype)
        { 
            this.size = (data == null) ? 0 : data.Length;
            this.type = tokentype;
            this.token = data;
        } 

        public SecurityBuffer(int size, BufferType tokentype) 
        { 
            this.size = size;
            this.type = tokentype; 
            this.token = size == 0 ? null : DiagnosticUtility.Utility.AllocateByteArray(size);
        }

        public SecurityBuffer( ChannelBinding channelBinding ) 
        {
            this.size = channelBinding.Size; 
            this.type = BufferType.ChannelBindings; 
            this.unmanagedToken = channelBinding;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK