The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Channels.Tcp \ TcpReadingStream

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. //============================================================
  16. //
  17. // File: TcpStreams.cs
  18. //
  19. // Summary: Defines streams used by TCP channel.
  20. //
  21. //============================================================
  22. using System;
  23. using System.Collections;
  24. using System.IO;
  25. using System.Net;
  26. using System.Net.Sockets;
  27. using System.Text;
  28. using System.Threading;
  29. using System.Globalization;
  30. namespace System.Runtime.Remoting.Channels.Tcp
  31. {
  32.    
  33.     internal abstract class TcpReadingStream : Stream
  34.     {
  35.         public void ReadToEnd()
  36.         {
  37.             // This method should never be called where it would be valid
  38.             // to use this data, so it is ok to throw the excess bytes
  39.             // away.
  40.             byte[] buffer = new byte[64];
  41.             int readCount;
  42.             do {
  43.                 readCount = Read(buffer, 0, 64);
  44.             }
  45.             while (readCount > 0);
  46.         }
  47.        
  48.         public virtual bool FoundEnd {
  49.             get { return false; }
  50.         }
  51.        
  52.         public override bool CanRead {
  53.             get { return true; }
  54.         }
  55.         public override bool CanSeek {
  56.             get { return false; }
  57.         }
  58.         public override bool CanWrite {
  59.             get { return false; }
  60.         }
  61.        
  62.         public override long Length {
  63.             get {
  64.                 throw new NotSupportedException();
  65.             }
  66.         }
  67.        
  68.         public override long Position {
  69.             get {
  70.                 throw new NotSupportedException();
  71.             }
  72.             set {
  73.                 throw new NotSupportedException();
  74.             }
  75.         }
  76.        
  77.         public override void Flush()
  78.         {
  79.             throw new NotSupportedException();
  80.         }
  81.        
  82.         public override long Seek(long offset, SeekOrigin origin)
  83.         {
  84.             throw new NotSupportedException();
  85.         }
  86.         public override void SetLength(long value)
  87.         {
  88.             throw new NotSupportedException();
  89.         }
  90.        
  91.         public override void Write(byte[] buffer, int offset, int count)
  92.         {
  93.             throw new NotSupportedException();
  94.         }
  95.        
  96.     }
  97.     // TcpReadingStream
  98.    
  99.     internal sealed class TcpFixedLengthReadingStream : TcpReadingStream
  100.     {
  101.         private SocketHandler _inputStream;
  102.         private int _bytesLeft;
  103.         // bytes left to read
  104.         internal TcpFixedLengthReadingStream(SocketHandler inputStream, int contentLength)
  105.         {
  106.             _inputStream = inputStream;
  107.             _bytesLeft = contentLength;
  108.         }
  109.         // TcpFixedLengthReadingStream
  110.         public override bool FoundEnd {
  111.             get { return _bytesLeft == 0; }
  112.         }
  113.        
  114.         protected override void Dispose(bool disposing)
  115.         {
  116.             try {
  117.                 if (disposing)
  118.                     _inputStream.OnInputStreamClosed();
  119.             }
  120.             finally {
  121.                 base.Dispose(disposing);
  122.             }
  123.         }
  124.        
  125.         public override int Read(byte[] buffer, int offset, int count)
  126.         {
  127.             if (_bytesLeft == 0)
  128.                 return 0;
  129.            
  130.             int readCount = _inputStream.Read(buffer, offset, Math.Min(_bytesLeft, count));
  131.             if (readCount > 0)
  132.                 _bytesLeft -= readCount;
  133.            
  134.             return readCount;
  135.         }
  136.         // Read
  137.         public override int ReadByte()
  138.         {
  139.             if (_bytesLeft == 0)
  140.                 return -1;
  141.            
  142.             _bytesLeft -= 1;
  143.             return _inputStream.ReadByte();
  144.         }
  145.         // ReadByte
  146.     }
  147.     // TcpFixedLengthReadingStream
  148.    
  149.     internal sealed class TcpChunkedReadingStream : TcpReadingStream
  150.     {
  151.         private SocketHandler _inputStream = null;
  152.         // read chunked tcp data from here
  153.         private int _bytesLeft;
  154.         // bytes left in current chunk
  155.         private bool _bFoundEnd = false;
  156.         // has end of stream been reached?
  157.         private byte[] _byteBuffer = new byte[1];
  158.         // buffer for reading bytes
  159.        
  160.         internal TcpChunkedReadingStream(SocketHandler inputStream)
  161.         {
  162.             _inputStream = inputStream;
  163.            
  164.             _bytesLeft = 0;
  165.         }
  166.         // HttpChunkedRequestStream
  167.         public override bool FoundEnd {
  168.             get { return _bFoundEnd; }
  169.         }
  170.        
  171.         protected override void Dispose(bool disposing)
  172.         {
  173.             try {
  174.             }
  175.             finally {
  176.                 base.Dispose(disposing);
  177.             }
  178.         }
  179.         // Close
  180.         public override int Read(byte[] buffer, int offset, int count)
  181.         {
  182.             int bytesRead = 0;
  183.            
  184.             while (!_bFoundEnd && (count > 0)) {
  185.                 // see if we need to start reading a new chunk
  186.                 if (_bytesLeft == 0) {
  187.                     _bytesLeft = _inputStream.ReadInt32();
  188.                    
  189.                     if (_bytesLeft == 0) {
  190.                         ReadTrailer();
  191.                         _bFoundEnd = true;
  192.                     }
  193.                 }
  194.                
  195.                 if (!_bFoundEnd) {
  196.                     int readCount = Math.Min(_bytesLeft, count);
  197.                     int bytesReadThisTime = _inputStream.Read(buffer, offset, readCount);
  198.                     if (bytesReadThisTime <= 0) {
  199.                         throw new RemotingException(CoreChannel.GetResourceString("Remoting_Tcp_ChunkedEncodingError"));
  200.                     }
  201.                    
  202.                     _bytesLeft -= bytesReadThisTime;
  203.                     count -= bytesReadThisTime;
  204.                     offset += bytesReadThisTime;
  205.                     bytesRead += bytesReadThisTime;
  206.                    
  207.                     // see if the end of the chunk was found
  208.                     if (_bytesLeft == 0) {
  209.                         ReadTrailer();
  210.                     }
  211.                 }
  212.             }
  213.             // while (count > 0)
  214.             return bytesRead;
  215.         }
  216.         // Read
  217.         public override int ReadByte()
  218.         {
  219.             int readCount = Read(_byteBuffer, 0, 1);
  220.             if (readCount == 0)
  221.                 return -1;
  222.            
  223.             return _byteBuffer[0];
  224.         }
  225.         // ReadByte
  226.        
  227.         private void ReadTrailer()
  228.         {
  229.             // read trailer bytes "\r\n" and throw an exception if they aren't correct.
  230.             int ch = _inputStream.ReadByte();
  231.             if (ch != '\r') {
  232.                 throw new RemotingException(CoreChannel.GetResourceString("Remoting_Tcp_ChunkedEncodingError"));
  233.             }
  234.            
  235.             ch = _inputStream.ReadByte();
  236.             if (ch != '\n') {
  237.                 throw new RemotingException(CoreChannel.GetResourceString("Remoting_Tcp_ChunkedEncodingError"));
  238.             }
  239.         }
  240.        
  241.     }
  242.     // TcpChunkedReadingStream
  243.    
  244.    
  245.    
  246.     // Maintains control of a socket connection.
  247.     internal sealed class TcpServerSocketHandler : TcpSocketHandler
  248.     {
  249.         // prebaked bytes
  250.         private static byte[] s_endOfLineBytes = Encoding.ASCII.GetBytes("\r\n");
  251.        
  252.        
  253.         // Used to keep track of socket connections
  254.         private static Int64 _connectionIdCounter = 0;
  255.        
  256.         private Int64 _connectionId;
  257.         // id for this connection
  258.         private bool _bOneWayRequest;
  259.         // is the incoming request one way?
  260.         private bool _bChunked;
  261.         // is the incoming request chunked?
  262.         private int _contentLength;
  263.         // content length of incoming request
  264.         TcpReadingStream _requestStream;
  265.         // the request stream
  266.        
  267.         internal TcpServerSocketHandler(Socket socket, RequestQueue requestQueue, Stream stream) : base(socket, requestQueue, stream)
  268.         {
  269.             _connectionId = Interlocked.Increment(ref _connectionIdCounter);
  270.         }
  271.         // TcpServerSocketHandler
  272.        
  273.         // Determine if it's possible to service another request
  274.         public bool CanServiceAnotherRequest()
  275.         {
  276.             return true;
  277.         }
  278.         // CanServiceAnotherRequest
  279.        
  280.         // Prepare for reading a new request off of the same socket
  281.         protected override void PrepareForNewMessage()
  282.         {
  283.             if (_requestStream != null) {
  284.                 if (!_requestStream.FoundEnd)
  285.                     _requestStream.ReadToEnd();
  286.                 _requestStream = null;
  287.             }
  288.         }
  289.         // PrepareForNewRequest
  290.         protected override void SendErrorMessageIfPossible(Exception e)
  291.         {
  292.             // A fatal exception occurred. We communicate this error by
  293.             // writing an error message and empty message body.
  294.             try {
  295.                 SendErrorResponse(e, true);
  296.             }
  297.             catch {
  298.                 // the connection must be dead, so it doesn't really matter.
  299.             }
  300.         }
  301.         // SendErrorMessageIfPossible
  302.        
  303.         // read headers
  304.         public ITransportHeaders ReadHeaders()
  305.         {
  306.             BaseTransportHeaders headers = new BaseTransportHeaders();
  307.            
  308.             UInt16 operation;
  309.             ReadVersionAndOperation(out operation);
  310.            
  311.             // make sure the operation is Request or OneWayRequest.
  312.             if (operation == TcpOperations.Request) {
  313.                 _bOneWayRequest = false;
  314.             }
  315.             else if (operation == TcpOperations.OneWayRequest) {
  316.                 _bOneWayRequest = true;
  317.             }
  318.             else {
  319.                 throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Tcp_ExpectingRequestOp"), operation.ToString(CultureInfo.CurrentCulture)));
  320.             }
  321.            
  322.             // content length must come next (may be chunked or a specific length)
  323.             ReadContentLength(out _bChunked, out _contentLength);
  324.            
  325.             // read to end of headers
  326.             ReadToEndOfHeaders(headers);
  327.            
  328.             // add IP address and Connection Id to headers
  329.             headers.IPAddress = ((IPEndPoint)NetSocket.RemoteEndPoint).Address;
  330.             headers.ConnectionId = _connectionId;
  331.            
  332.             return headers;
  333.         }
  334.         // ReadHeaders
  335.        
  336.         public Stream GetRequestStream()
  337.         {
  338.             if (!_bChunked)
  339.                 _requestStream = new TcpFixedLengthReadingStream(this, _contentLength);
  340.             else
  341.                 _requestStream = new TcpChunkedReadingStream(this);
  342.             return _requestStream;
  343.         }
  344.         // GetRequestStream
  345.        
  346.         public void SendResponse(ITransportHeaders headers, Stream contentStream)
  347.         {
  348.             // bail out if the original request was OneWay (means the client doesn't even
  349.             // want or expect to receive responses or error messages)
  350.             if (_bOneWayRequest)
  351.                 return;
  352.            
  353.             // build up headers and send
  354.             ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool);
  355.            
  356.             // output preamble and version
  357.             WritePreambleAndVersion(headerStream);
  358.             // output opcode
  359.             WriteUInt16(TcpOperations.Reply, headerStream);
  360.             // output content length delimiter
  361.             WriteUInt16(TcpContentDelimiter.ContentLength, headerStream);
  362.             WriteInt32((int)contentStream.Length, headerStream);
  363.            
  364.             // No status code header is needed because if we're in this code path
  365.             // the data transfer succeeded as far as the transport protocol is
  366.             // concerned (and the success status code is optional).
  367.            
  368.             WriteHeaders(headers, headerStream);
  369.            
  370.             headerStream.WriteTo(NetStream);
  371.             headerStream.Close();
  372.            
  373.             StreamHelper.CopyStream(contentStream, NetStream);
  374.            
  375.             contentStream.Close();
  376.         }
  377.         // SendResponse
  378.         string GenerateFaultString(Exception e)
  379.         {
  380.             //If the user has specified it's a development server (versus a production server) in remoting config,
  381.             //then we should just return e.ToString instead of extracting the list of messages.
  382.             if (!CustomErrorsEnabled())
  383.                 return e.ToString();
  384.             else {
  385.                 return CoreChannel.GetResourceString("Remoting_InternalError");
  386.             }
  387.         }
  388.        
  389.         public void SendErrorResponse(Exception e, bool bCloseConnection)
  390.         {
  391.             SendErrorResponse(GenerateFaultString(e), bCloseConnection);
  392.         }
  393.        
  394.         public void SendErrorResponse(string e, bool bCloseConnection)
  395.         {
  396.             // bail out if the original request was OneWay (means the client doesn't even
  397.             // want or expect to receive responses or error messages)
  398.             if (_bOneWayRequest)
  399.                 return;
  400.            
  401.             // build up headers and send
  402.             ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool);
  403.            
  404.             // output preamble and version
  405.             WritePreambleAndVersion(headerStream);
  406.             // output opcode
  407.             WriteUInt16(TcpOperations.Reply, headerStream);
  408.             // output content length delimiter (0-length stream)
  409.             WriteUInt16(TcpContentDelimiter.ContentLength, headerStream);
  410.             WriteInt32(0, headerStream);
  411.            
  412.             // output status code and reason
  413.             WriteUInt16(TcpHeaders.StatusCode, headerStream);
  414.             WriteByte(TcpHeaderFormat.UInt16, headerStream);
  415.             WriteUInt16(TcpStatusCode.GenericError, headerStream);
  416.             // we purposely don't include the stack trace to avoid giving
  417.             // out too much information for security purposes.
  418.             WriteUInt16(TcpHeaders.StatusPhrase, headerStream);
  419.             WriteByte(TcpHeaderFormat.CountedString, headerStream);
  420.             WriteCountedString(e, headerStream);
  421.            
  422.             // indicate that we are about to close the connection
  423.             WriteUInt16(TcpHeaders.CloseConnection, headerStream);
  424.             WriteByte(TcpHeaderFormat.Void, headerStream);
  425.            
  426.             // end of headers
  427.             WriteUInt16(TcpHeaders.EndOfHeaders, headerStream);
  428.            
  429.             headerStream.WriteTo(NetStream);
  430.             headerStream.Close();
  431.         }
  432.         // SendErrorResponse
  433.        
  434.     }
  435.     // class TcpServerSocketHandler
  436.    
  437.    
  438.    
  439. }
  440. // namespace System.Runtime.Remoting.Channels.Tcp

Developer Fusion