_NegoStream.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 / fx / src / Net / System / Net / SecureProtocols / _NegoStream.cs / 1305376 / _NegoStream.cs

                            /*++ 
Copyright (c) Microsoft Corporation

Module Name:
 
    _NegoStream.cs
 
Abstract: 
    The class is used to encrypt/decrypt user data based on established
    security context. Presumably the context belongs to SSPI NEGO or NTLM package. 

Author:
    Alexei Vopilov    12-Aug-2003
 
Revision History:
    12-Aug-2003 New design that has obsoleted Authenticator class 
    15-Jan-2004 Converted to a partial class, only internal NegotiateStream implementaion goes into this file. 

--*/ 

namespace System.Net.Security {
    using System;
    using System.IO; 
    using System.Security;
    using System.Security.Principal; 
    using System.Security.Permissions; 
    using System.Threading;
 
    //
    // This is a wrapping stream that does data encryption/decryption based on a successfully authenticated SSPI context.
    //
    public partial class NegotiateStream: AuthenticatedStream 
    {
        private static AsyncCallback _WriteCallback = new AsyncCallback(WriteCallback); 
        private static AsyncProtocolCallback _ReadCallback  = new AsyncProtocolCallback(ReadCallback); 

        private int         _NestedWrite; 
        private int         _NestedRead;
        private byte[]      _ReadHeader;

        // never updated directly, special properties are used 
        private byte[]      _InternalBuffer;
        private int         _InternalOffset; 
        private int         _InternalBufferCount; 

        FixedSizeReader     _FrameReader; 

        //
        // Private implemenation
        // 

        private void InitializeStreamPart() 
        { 
            _ReadHeader = new byte[4];
            _FrameReader = new FixedSizeReader(InnerStream); 
        }

        //
        // 
        private byte[] InternalBuffer {
            get { 
                return _InternalBuffer; 
            }
        } 
        //
        //
        private int InternalOffset {
            get { 
                return _InternalOffset;
            } 
        } 
        //
        private int InternalBufferCount { 
            get {
                return _InternalBufferCount;
            }
        } 
        //
        // 
        private void DecrementInternalBufferCount(int decrCount) 
        {
            _InternalOffset += decrCount; 
            _InternalBufferCount -= decrCount;
        }
        //
        // 
        private void EnsureInternalBufferSize(int bytes)
        { 
            _InternalBufferCount = bytes; 
            _InternalOffset = 0;
            if (InternalBuffer == null || InternalBuffer.Length < bytes) 
            {
                _InternalBuffer = new byte[bytes];
            }
        } 
        //
        private void AdjustInternalBufferOffsetSize(int bytes, int offset) 
        { 
            _InternalBufferCount = bytes;
            _InternalOffset = offset; 
        }
        //
        // Validates user parameteres for all Read/Write methods
        // 
        private void ValidateParameters(byte[] buffer, int offset, int count)
        { 
            if (buffer == null) 
                throw new ArgumentNullException("buffer");
 
            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset");

            if (count < 0) 
                throw new ArgumentOutOfRangeException("count");
 
            if (count > buffer.Length-offset) 
                throw new ArgumentOutOfRangeException("count", SR.GetString(SR.net_offset_plus_count));
        } 
        //
        // Combined [....]/async write method. For [....] requet asyncRequest==null
        //
        private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        {
            ValidateParameters(buffer, offset, count); 
 
            if (Interlocked.Exchange(ref _NestedWrite, 1) == 1)
            { 
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null? "BeginWrite":"Write"), "write"));
            }

 
            bool failed = false;
            try 
            { 
                StartWriting(buffer, offset, count, asyncRequest);
            } 
            catch (Exception e)
            {
                failed = true;
                if (e is IOException) { 
                    throw;
                } 
                throw new IOException(SR.GetString(SR.net_io_write), e); 
            }
            finally 
            {
                if (asyncRequest == null || failed)
                {
                    _NestedWrite = 0; 
                }
            } 
        } 
        //
        // 
        //
        private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            // We loop to this method from the callback 
            // If the last chunk was just completed from async callback (count < 0), we complete user request
            if (count >= 0 ) 
            { 
                byte[] outBuffer = null;
                do 
                {
                    int chunkBytes = Math.Min(count, NegoState.c_MaxWriteDataSize);
                    int encryptedBytes;
 
                    try {
                        encryptedBytes = _NegoState.EncryptData(buffer, offset, chunkBytes, ref outBuffer); 
                    } 
                    catch (Exception e) {
                        throw new IOException(SR.GetString(SR.net_io_encrypt), e); 
                    }

                    if (asyncRequest != null)
                    { 
                        // prepare for the next request
                        asyncRequest.SetNextRequest(buffer, offset+chunkBytes, count-chunkBytes, null); 
                        IAsyncResult ar = InnerStream.BeginWrite(outBuffer, 0, encryptedBytes, _WriteCallback, asyncRequest); 
                        if (!ar.CompletedSynchronously)
                        { 
                            return;
                        }
                        InnerStream.EndWrite(ar);
 
                    }
                    else 
                    { 
                        InnerStream.Write(outBuffer, 0, encryptedBytes);
                    } 
                    offset += chunkBytes;
                    count  -= chunkBytes;
                } while (count != 0);
            } 

            if (asyncRequest != null) { 
                asyncRequest.CompleteUser(); 
            }
        } 
        //
        // Combined [....]/async read method. For [....] requet asyncRequest==null
        // There is a little overheader because we need to pass buffer/offset/count used only in [....].
        // Still the benefit is that we have a common [....]/async code path. 
        //
        private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        { 
            ValidateParameters(buffer, offset, count);
 
            if (Interlocked.Exchange(ref _NestedRead, 1) == 1)
            {
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest!=null? "BeginRead":"Read"), "read"));
            } 

            bool failed = false; 
            try 
            {
                if (InternalBufferCount != 0) 
                {
                    int copyBytes = InternalBufferCount > count? count:InternalBufferCount;
                    if (copyBytes != 0)
                    { 
                        Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, copyBytes);
                        DecrementInternalBufferCount(copyBytes); 
                    } 
                    if (asyncRequest != null) {
                        asyncRequest.CompleteUser((object) copyBytes); 
                    }
                    return copyBytes;
                }
                // going into real IO 
                return StartReading(buffer, offset, count, asyncRequest);
            } 
            catch (Exception e) 
            {
                failed = true; 
                if (e is IOException) {
                    throw;
                }
                throw new IOException(SR.GetString(SR.net_io_read), e); 
            }
            finally 
            { 
                // if [....] request or exception
                if (asyncRequest == null || failed) 
                {
                    _NestedRead = 0;
                }
            } 
        }
        // 
        // To avoid recursion when decrypted 0 bytes this method will loop until decryption resulted at least in 1 byte. 
        //
        private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        {
            int result;
            // When we read -1 bytes means we have decrypted 0 bytes, need looping.
            while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1) { 
                ;
            } 
            return result; 
        }
 
        //
        // Need read frame size first
        //
        private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        {
            int readBytes = 0; 
            if (asyncRequest != null) 
            {
                asyncRequest.SetNextRequest(_ReadHeader, 0, _ReadHeader.Length, _ReadCallback); 
                _FrameReader.AsyncReadPacket(asyncRequest);
                if (!asyncRequest.MustCompleteSynchronously)
                {
                    return 0; 
                }
                readBytes = asyncRequest.Result; 
            } 
            else
            { 
                readBytes = _FrameReader.ReadPacket(_ReadHeader, 0, _ReadHeader.Length);
            }
            return StartFrameBody(readBytes, buffer, offset, count, asyncRequest);
        } 
        //
        // 
        // 
        private int StartFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        { 
            if (readBytes == 0)
            {
                //EOF
                if (asyncRequest != null) 
                {
                    asyncRequest.CompleteUser((object)0); 
                } 
                return 0;
            } 
            GlobalLog.Assert(readBytes == _ReadHeader.Length, "NegoStream::ProcessHeader()|Frame size must be 4 but received {0} bytes.", readBytes);

            //rpelace readBytes with the body size recovered from the header content
            readBytes =  _ReadHeader[3]; 
            readBytes = (readBytes<<8) | _ReadHeader[2];
            readBytes = (readBytes<<8) | _ReadHeader[1]; 
            readBytes = (readBytes<<8) | _ReadHeader[0]; 

            // 
            // The body carries 4 bytes for trailer size slot plus trailer, hence <=4 frame size is always an error.
            // Additionally we'd like to restrice the read frame size to modest 64k
            //
            if (readBytes <= 4 || readBytes > NegoState.c_MaxReadFrameSize) 
            {
                throw new IOException(SR.GetString(SR.net_frame_read_size)); 
            } 

            // 
            // Always pass InternalBuffer for SSPI "in place" decryption.
            // A user buffer can be shared by many threads in that case decryption/integrity check may fail cause of data corruption.
            //
            EnsureInternalBufferSize(readBytes); 
            if (asyncRequest != null) //Async
            { 
                asyncRequest.SetNextRequest(InternalBuffer, 0, readBytes, _ReadCallback); 

                _FrameReader.AsyncReadPacket(asyncRequest); 

                if (!asyncRequest.MustCompleteSynchronously)
                {
                    return 0; 
                }
                readBytes = asyncRequest.Result; 
            } 
            else //[....]
            { 
                readBytes = _FrameReader.ReadPacket(InternalBuffer, 0, readBytes);
            }
            return ProcessFrameBody(readBytes, buffer, offset, count, asyncRequest);
        } 
        //
        // 
        // 
        private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        { 
            if (readBytes == 0)
            {
                // We already checked that the frame body is bigger than 0 bytes
                // Hence, this is an EOF ... fire. 
                throw new IOException(SR.GetString(SR.net_io_eof));
            } 
 
            //Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_
            int internalOffset; 
            readBytes = _NegoState.DecryptData(InternalBuffer, 0, readBytes, out internalOffset);

            // Decrypted data start from zero offset, the size can be shrinked after decryption
            AdjustInternalBufferOffsetSize(readBytes, internalOffset); 

            if (readBytes == 0 && count != 0) 
            { 
                //Read again
                return -1; 
            }

            if (readBytes > count)
            { 
                readBytes = count;
            } 
            Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, readBytes); 

            // This will adjust both the remaining internal buffer count and the offset 
            DecrementInternalBufferCount(readBytes);

            if (asyncRequest != null)
            { 
                asyncRequest.CompleteUser((object)readBytes);
            } 
 
            return readBytes;
        } 
        //
        //
        //
        private static void WriteCallback(IAsyncResult transportResult) 
        {
            if (transportResult.CompletedSynchronously) 
            { 
                return;
            } 
            GlobalLog.Assert(transportResult.AsyncState is AsyncProtocolRequest , "NegotiateSteam::WriteCallback|State type is wrong, expected AsyncProtocolRequest.");

            AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest) transportResult.AsyncState;
 
            try {
                NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject; 
                negoStream.InnerStream.EndWrite(transportResult); 
                if (asyncRequest.Count == 0) {
                    // this was the last chunk 
                    asyncRequest.Count = -1;
                }
                negoStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest);
 
            }
            catch (Exception e) { 
                if (asyncRequest.IsUserCompleted) { 
                    // This will throw on a worker thread.
                    throw; 
                }
                asyncRequest.CompleteWithError(e);
            }
        } 
        //
        // 
        private static void ReadCallback(AsyncProtocolRequest asyncRequest) 
        {
            // Async ONLY completion 
            try
            {
                NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject;
                BufferAsyncResult bufferResult = (BufferAsyncResult) asyncRequest.UserAsyncResult; 

                // This is not a hack, just optimization to avoid an additional callback. 
                // 
                if ((object) asyncRequest.Buffer == (object)negoStream._ReadHeader)
                { 
                    negoStream.StartFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest);
                }
                else
                { 
                    if (-1 == negoStream.ProcessFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest))
                    { 
                        // in case we decrypted 0 bytes start another reading. 
                        negoStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest);
 
                    }
                }
            }
            catch (Exception e) 
            {
                if (asyncRequest.IsUserCompleted) { 
                    // This will throw on a worker thread. 
                    throw;
                } 
                asyncRequest.CompleteWithError(e);
            }
        }
    } 
}

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

Module Name:
 
    _NegoStream.cs
 
Abstract: 
    The class is used to encrypt/decrypt user data based on established
    security context. Presumably the context belongs to SSPI NEGO or NTLM package. 

Author:
    Alexei Vopilov    12-Aug-2003
 
Revision History:
    12-Aug-2003 New design that has obsoleted Authenticator class 
    15-Jan-2004 Converted to a partial class, only internal NegotiateStream implementaion goes into this file. 

--*/ 

namespace System.Net.Security {
    using System;
    using System.IO; 
    using System.Security;
    using System.Security.Principal; 
    using System.Security.Permissions; 
    using System.Threading;
 
    //
    // This is a wrapping stream that does data encryption/decryption based on a successfully authenticated SSPI context.
    //
    public partial class NegotiateStream: AuthenticatedStream 
    {
        private static AsyncCallback _WriteCallback = new AsyncCallback(WriteCallback); 
        private static AsyncProtocolCallback _ReadCallback  = new AsyncProtocolCallback(ReadCallback); 

        private int         _NestedWrite; 
        private int         _NestedRead;
        private byte[]      _ReadHeader;

        // never updated directly, special properties are used 
        private byte[]      _InternalBuffer;
        private int         _InternalOffset; 
        private int         _InternalBufferCount; 

        FixedSizeReader     _FrameReader; 

        //
        // Private implemenation
        // 

        private void InitializeStreamPart() 
        { 
            _ReadHeader = new byte[4];
            _FrameReader = new FixedSizeReader(InnerStream); 
        }

        //
        // 
        private byte[] InternalBuffer {
            get { 
                return _InternalBuffer; 
            }
        } 
        //
        //
        private int InternalOffset {
            get { 
                return _InternalOffset;
            } 
        } 
        //
        private int InternalBufferCount { 
            get {
                return _InternalBufferCount;
            }
        } 
        //
        // 
        private void DecrementInternalBufferCount(int decrCount) 
        {
            _InternalOffset += decrCount; 
            _InternalBufferCount -= decrCount;
        }
        //
        // 
        private void EnsureInternalBufferSize(int bytes)
        { 
            _InternalBufferCount = bytes; 
            _InternalOffset = 0;
            if (InternalBuffer == null || InternalBuffer.Length < bytes) 
            {
                _InternalBuffer = new byte[bytes];
            }
        } 
        //
        private void AdjustInternalBufferOffsetSize(int bytes, int offset) 
        { 
            _InternalBufferCount = bytes;
            _InternalOffset = offset; 
        }
        //
        // Validates user parameteres for all Read/Write methods
        // 
        private void ValidateParameters(byte[] buffer, int offset, int count)
        { 
            if (buffer == null) 
                throw new ArgumentNullException("buffer");
 
            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset");

            if (count < 0) 
                throw new ArgumentOutOfRangeException("count");
 
            if (count > buffer.Length-offset) 
                throw new ArgumentOutOfRangeException("count", SR.GetString(SR.net_offset_plus_count));
        } 
        //
        // Combined [....]/async write method. For [....] requet asyncRequest==null
        //
        private void ProcessWrite(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        {
            ValidateParameters(buffer, offset, count); 
 
            if (Interlocked.Exchange(ref _NestedWrite, 1) == 1)
            { 
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest != null? "BeginWrite":"Write"), "write"));
            }

 
            bool failed = false;
            try 
            { 
                StartWriting(buffer, offset, count, asyncRequest);
            } 
            catch (Exception e)
            {
                failed = true;
                if (e is IOException) { 
                    throw;
                } 
                throw new IOException(SR.GetString(SR.net_io_write), e); 
            }
            finally 
            {
                if (asyncRequest == null || failed)
                {
                    _NestedWrite = 0; 
                }
            } 
        } 
        //
        // 
        //
        private void StartWriting(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        {
            // We loop to this method from the callback 
            // If the last chunk was just completed from async callback (count < 0), we complete user request
            if (count >= 0 ) 
            { 
                byte[] outBuffer = null;
                do 
                {
                    int chunkBytes = Math.Min(count, NegoState.c_MaxWriteDataSize);
                    int encryptedBytes;
 
                    try {
                        encryptedBytes = _NegoState.EncryptData(buffer, offset, chunkBytes, ref outBuffer); 
                    } 
                    catch (Exception e) {
                        throw new IOException(SR.GetString(SR.net_io_encrypt), e); 
                    }

                    if (asyncRequest != null)
                    { 
                        // prepare for the next request
                        asyncRequest.SetNextRequest(buffer, offset+chunkBytes, count-chunkBytes, null); 
                        IAsyncResult ar = InnerStream.BeginWrite(outBuffer, 0, encryptedBytes, _WriteCallback, asyncRequest); 
                        if (!ar.CompletedSynchronously)
                        { 
                            return;
                        }
                        InnerStream.EndWrite(ar);
 
                    }
                    else 
                    { 
                        InnerStream.Write(outBuffer, 0, encryptedBytes);
                    } 
                    offset += chunkBytes;
                    count  -= chunkBytes;
                } while (count != 0);
            } 

            if (asyncRequest != null) { 
                asyncRequest.CompleteUser(); 
            }
        } 
        //
        // Combined [....]/async read method. For [....] requet asyncRequest==null
        // There is a little overheader because we need to pass buffer/offset/count used only in [....].
        // Still the benefit is that we have a common [....]/async code path. 
        //
        private int ProcessRead(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        { 
            ValidateParameters(buffer, offset, count);
 
            if (Interlocked.Exchange(ref _NestedRead, 1) == 1)
            {
                throw new NotSupportedException(SR.GetString(SR.net_io_invalidnestedcall, (asyncRequest!=null? "BeginRead":"Read"), "read"));
            } 

            bool failed = false; 
            try 
            {
                if (InternalBufferCount != 0) 
                {
                    int copyBytes = InternalBufferCount > count? count:InternalBufferCount;
                    if (copyBytes != 0)
                    { 
                        Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, copyBytes);
                        DecrementInternalBufferCount(copyBytes); 
                    } 
                    if (asyncRequest != null) {
                        asyncRequest.CompleteUser((object) copyBytes); 
                    }
                    return copyBytes;
                }
                // going into real IO 
                return StartReading(buffer, offset, count, asyncRequest);
            } 
            catch (Exception e) 
            {
                failed = true; 
                if (e is IOException) {
                    throw;
                }
                throw new IOException(SR.GetString(SR.net_io_read), e); 
            }
            finally 
            { 
                // if [....] request or exception
                if (asyncRequest == null || failed) 
                {
                    _NestedRead = 0;
                }
            } 
        }
        // 
        // To avoid recursion when decrypted 0 bytes this method will loop until decryption resulted at least in 1 byte. 
        //
        private int StartReading(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        {
            int result;
            // When we read -1 bytes means we have decrypted 0 bytes, need looping.
            while ((result = StartFrameHeader(buffer, offset, count, asyncRequest)) == -1) { 
                ;
            } 
            return result; 
        }
 
        //
        // Need read frame size first
        //
        private int StartFrameHeader(byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest) 
        {
            int readBytes = 0; 
            if (asyncRequest != null) 
            {
                asyncRequest.SetNextRequest(_ReadHeader, 0, _ReadHeader.Length, _ReadCallback); 
                _FrameReader.AsyncReadPacket(asyncRequest);
                if (!asyncRequest.MustCompleteSynchronously)
                {
                    return 0; 
                }
                readBytes = asyncRequest.Result; 
            } 
            else
            { 
                readBytes = _FrameReader.ReadPacket(_ReadHeader, 0, _ReadHeader.Length);
            }
            return StartFrameBody(readBytes, buffer, offset, count, asyncRequest);
        } 
        //
        // 
        // 
        private int StartFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        { 
            if (readBytes == 0)
            {
                //EOF
                if (asyncRequest != null) 
                {
                    asyncRequest.CompleteUser((object)0); 
                } 
                return 0;
            } 
            GlobalLog.Assert(readBytes == _ReadHeader.Length, "NegoStream::ProcessHeader()|Frame size must be 4 but received {0} bytes.", readBytes);

            //rpelace readBytes with the body size recovered from the header content
            readBytes =  _ReadHeader[3]; 
            readBytes = (readBytes<<8) | _ReadHeader[2];
            readBytes = (readBytes<<8) | _ReadHeader[1]; 
            readBytes = (readBytes<<8) | _ReadHeader[0]; 

            // 
            // The body carries 4 bytes for trailer size slot plus trailer, hence <=4 frame size is always an error.
            // Additionally we'd like to restrice the read frame size to modest 64k
            //
            if (readBytes <= 4 || readBytes > NegoState.c_MaxReadFrameSize) 
            {
                throw new IOException(SR.GetString(SR.net_frame_read_size)); 
            } 

            // 
            // Always pass InternalBuffer for SSPI "in place" decryption.
            // A user buffer can be shared by many threads in that case decryption/integrity check may fail cause of data corruption.
            //
            EnsureInternalBufferSize(readBytes); 
            if (asyncRequest != null) //Async
            { 
                asyncRequest.SetNextRequest(InternalBuffer, 0, readBytes, _ReadCallback); 

                _FrameReader.AsyncReadPacket(asyncRequest); 

                if (!asyncRequest.MustCompleteSynchronously)
                {
                    return 0; 
                }
                readBytes = asyncRequest.Result; 
            } 
            else //[....]
            { 
                readBytes = _FrameReader.ReadPacket(InternalBuffer, 0, readBytes);
            }
            return ProcessFrameBody(readBytes, buffer, offset, count, asyncRequest);
        } 
        //
        // 
        // 
        private int ProcessFrameBody(int readBytes, byte[] buffer, int offset, int count, AsyncProtocolRequest asyncRequest)
        { 
            if (readBytes == 0)
            {
                // We already checked that the frame body is bigger than 0 bytes
                // Hence, this is an EOF ... fire. 
                throw new IOException(SR.GetString(SR.net_io_eof));
            } 
 
            //Decrypt into internal buffer, change "readBytes" to count now _Decrypted Bytes_
            int internalOffset; 
            readBytes = _NegoState.DecryptData(InternalBuffer, 0, readBytes, out internalOffset);

            // Decrypted data start from zero offset, the size can be shrinked after decryption
            AdjustInternalBufferOffsetSize(readBytes, internalOffset); 

            if (readBytes == 0 && count != 0) 
            { 
                //Read again
                return -1; 
            }

            if (readBytes > count)
            { 
                readBytes = count;
            } 
            Buffer.BlockCopy(InternalBuffer, InternalOffset, buffer, offset, readBytes); 

            // This will adjust both the remaining internal buffer count and the offset 
            DecrementInternalBufferCount(readBytes);

            if (asyncRequest != null)
            { 
                asyncRequest.CompleteUser((object)readBytes);
            } 
 
            return readBytes;
        } 
        //
        //
        //
        private static void WriteCallback(IAsyncResult transportResult) 
        {
            if (transportResult.CompletedSynchronously) 
            { 
                return;
            } 
            GlobalLog.Assert(transportResult.AsyncState is AsyncProtocolRequest , "NegotiateSteam::WriteCallback|State type is wrong, expected AsyncProtocolRequest.");

            AsyncProtocolRequest asyncRequest = (AsyncProtocolRequest) transportResult.AsyncState;
 
            try {
                NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject; 
                negoStream.InnerStream.EndWrite(transportResult); 
                if (asyncRequest.Count == 0) {
                    // this was the last chunk 
                    asyncRequest.Count = -1;
                }
                negoStream.StartWriting(asyncRequest.Buffer, asyncRequest.Offset, asyncRequest.Count, asyncRequest);
 
            }
            catch (Exception e) { 
                if (asyncRequest.IsUserCompleted) { 
                    // This will throw on a worker thread.
                    throw; 
                }
                asyncRequest.CompleteWithError(e);
            }
        } 
        //
        // 
        private static void ReadCallback(AsyncProtocolRequest asyncRequest) 
        {
            // Async ONLY completion 
            try
            {
                NegotiateStream negoStream = (NegotiateStream)asyncRequest.AsyncObject;
                BufferAsyncResult bufferResult = (BufferAsyncResult) asyncRequest.UserAsyncResult; 

                // This is not a hack, just optimization to avoid an additional callback. 
                // 
                if ((object) asyncRequest.Buffer == (object)negoStream._ReadHeader)
                { 
                    negoStream.StartFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest);
                }
                else
                { 
                    if (-1 == negoStream.ProcessFrameBody(asyncRequest.Result, bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest))
                    { 
                        // in case we decrypted 0 bytes start another reading. 
                        negoStream.StartReading(bufferResult.Buffer, bufferResult.Offset, bufferResult.Count, asyncRequest);
 
                    }
                }
            }
            catch (Exception e) 
            {
                if (asyncRequest.IsUserCompleted) { 
                    // This will throw on a worker thread. 
                    throw;
                } 
                asyncRequest.CompleteWithError(e);
            }
        }
    } 
}

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

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