The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Channels \ SocketHandler

  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. // File: SocketManager.cs
  17. //
  18. // Summary: Class for managing a socket connection.
  19. //
  20. //==========================================================================
  21. using System;
  22. using System.IO;
  23. using System.Net;
  24. using System.Net.Sockets;
  25. using System.Runtime.Remoting.Messaging;
  26. using System.Security.Principal;
  27. using System.Text;
  28. using System.Threading;
  29. namespace System.Runtime.Remoting.Channels
  30. {
  31.     internal delegate bool ValidateByteDelegate(byte b);
  32.    
  33.    
  34.     internal abstract class SocketHandler
  35.     {
  36.         // socket manager data
  37.         protected Socket NetSocket;
  38.         // network socket
  39.         protected Stream NetStream;
  40.         // network stream
  41.         private DateTime _creationTime;
  42.         private RequestQueue _requestQueue;
  43.         // request queue to use for this connection
  44.         private byte[] _dataBuffer;
  45.         // buffered data
  46.         private int _dataBufferSize;
  47.         // size of data buffer
  48.         private int _dataOffset;
  49.         // offset of remaining data in buffer
  50.         private int _dataCount;
  51.         // count of remaining bytes in buffer
  52.         private AsyncCallback _beginReadCallback;
  53.         // callback to use when doing an async read
  54.         private IAsyncResult _beginReadAsyncResult;
  55.         // async result from doing a begin read
  56.         private WaitCallback _dataArrivedCallback;
  57.         // callback to signal once data is available
  58.         private object _dataArrivedCallbackState;
  59.         // state object to go along with callback
  60.         private byte[] _byteBuffer = new byte[4];
  61.         // buffer for reading bytes
  62.        
  63.         // control cookie -
  64.         // The control cookie is used for synchronization when a "user"
  65.         // wants to retrieve this client socket manager from the socket
  66.         // cache.
  67.         private int _controlCookie = 1;
  68.        
  69.        
  70.        
  71.         // hide default constructor
  72.         private SocketHandler()
  73.         {
  74.         }
  75.        
  76.         public SocketHandler(Socket socket, Stream netStream)
  77.         {
  78.             _beginReadCallback = new AsyncCallback(this.BeginReadMessageCallback);
  79.             _creationTime = DateTime.UtcNow;
  80.            
  81.             NetSocket = socket;
  82.             NetStream = netStream;
  83.            
  84.             _dataBuffer = CoreChannel.BufferPool.GetBuffer();
  85.             _dataBufferSize = _dataBuffer.Length;
  86.             _dataOffset = 0;
  87.             _dataCount = 0;
  88.         }
  89.         // SocketHandler
  90.         internal SocketHandler(Socket socket, RequestQueue requestQueue, Stream netStream) : this(socket, netStream)
  91.         {
  92.             _requestQueue = requestQueue;
  93.         }
  94.         // SocketHandler
  95.         public DateTime CreationTime {
  96.             get { return _creationTime; }
  97.         }
  98.        
  99.         // If this method returns true, then whoever called it can assume control
  100.         // of the client socket manager. If it returns false, the caller is on
  101.         // their honor not to do anything further with this object.
  102.         public bool RaceForControl()
  103.         {
  104.             if (1 == Interlocked.Exchange(ref _controlCookie, 0))
  105.                 return true;
  106.            
  107.             return false;
  108.         }
  109.         // RaceForControl
  110.         public void ReleaseControl()
  111.         {
  112.             _controlCookie = 1;
  113.         }
  114.         // ReleaseControl
  115.        
  116.         // Determines if the remote connection is from localhost.
  117.         internal bool IsLocalhost()
  118.         {
  119.             if (NetSocket == null || NetSocket.RemoteEndPoint == null)
  120.                 return true;
  121.            
  122.             IPAddress remoteAddr = ((IPEndPoint)NetSocket.RemoteEndPoint).Address;
  123.             return IPAddress.IsLoopback(remoteAddr) || CoreChannel.IsLocalIpAddress(remoteAddr);
  124.         }
  125.         // IsLocalhost
  126.         // Determines if the remote connection is from localhost.
  127.         internal bool IsLocal()
  128.         {
  129.             if (NetSocket == null)
  130.                 return true;
  131.            
  132.             IPAddress remoteAddr = ((IPEndPoint)NetSocket.RemoteEndPoint).Address;
  133.             return IPAddress.IsLoopback(remoteAddr);
  134.         }
  135.         // IsLocal
  136.         internal bool CustomErrorsEnabled()
  137.         {
  138.             try {
  139.                 return RemotingConfiguration.CustomErrorsEnabled(IsLocalhost());
  140.             }
  141.             catch {
  142.                 return true;
  143.             }
  144.         }
  145.        
  146.         // does any necessary cleanup before reading the incoming message
  147.         protected abstract void PrepareForNewMessage();
  148.        
  149.         // allows derived classes to send an error message if the async read
  150.         // in BeginReadMessage fails.
  151.         protected virtual void SendErrorMessageIfPossible(Exception e)
  152.         {
  153.         }
  154.        
  155.         // allows socket handler to do something when an input stream it handed
  156.         // out is closed. The input stream is responsible for calling this method.
  157.         // (usually, only client socket handlers will do anything with this).
  158.         // (input stream refers to data being read off of the network)
  159.         public virtual void OnInputStreamClosed()
  160.         {
  161.         }
  162.        
  163.        
  164.         public virtual void Close()
  165.         {
  166.             if (_requestQueue != null)
  167.                 _requestQueue.ScheduleMoreWorkIfNeeded();
  168.            
  169.             if (NetStream != null) {
  170.                 NetStream.Close();
  171.                 NetStream = null;
  172.             }
  173.            
  174.             if (NetSocket != null) {
  175.                 NetSocket.Close();
  176.                 NetSocket = null;
  177.             }
  178.            
  179.             // return buffer to the pool
  180.             if (_dataBuffer != null) {
  181.                 CoreChannel.BufferPool.ReturnBuffer(_dataBuffer);
  182.                 _dataBuffer = null;
  183.             }
  184.         }
  185.         // Close
  186.        
  187.         public WaitCallback DataArrivedCallback {
  188.             set { _dataArrivedCallback = value; }
  189.         }
  190.         // DataArrivedCallback
  191.         public object DataArrivedCallbackState {
  192.             get { return _dataArrivedCallbackState; }
  193.             set { _dataArrivedCallbackState = value; }
  194.         }
  195.         // DataArrivedCallbackState
  196.        
  197.         public void BeginReadMessage()
  198.         {
  199.             bool bProcessNow = false;
  200.            
  201.             try {
  202.                 if (_requestQueue != null)
  203.                     _requestQueue.ScheduleMoreWorkIfNeeded();
  204.                
  205.                 PrepareForNewMessage();
  206.                
  207.                 if (_dataCount == 0) {
  208.                     _beginReadAsyncResult = NetStream.BeginRead(_dataBuffer, 0, _dataBufferSize, _beginReadCallback, null);
  209.                 }
  210.                 else {
  211.                     // just queue the request if we already have some data
  212.                     // (note: we intentionally don't call the callback directly to avoid
  213.                     // overflowing the stack if we service a bunch of calls)
  214.                     bProcessNow = true;
  215.                 }
  216.             }
  217.             catch (Exception e) {
  218.                 CloseOnFatalError(e);
  219.             }
  220.             catch {
  221.                 CloseOnFatalError(new Exception(CoreChannel.GetResourceString("Remoting_nonClsCompliantException")));
  222.             }
  223.            
  224.             if (bProcessNow) {
  225.                 if (_requestQueue != null)
  226.                     _requestQueue.ProcessNextRequest(this);
  227.                 else
  228.                     ProcessRequestNow();
  229.                
  230.                 _beginReadAsyncResult = null;
  231.             }
  232.         }
  233.         // BeginReadMessage
  234.        
  235.         public void BeginReadMessageCallback(IAsyncResult ar)
  236.         {
  237.             bool bProcessRequest = false;
  238.            
  239.             // data has been buffered; proceed to call provided callback
  240.             try {
  241.                 _beginReadAsyncResult = null;
  242.                
  243.                 _dataOffset = 0;
  244.                 _dataCount = NetStream.EndRead(ar);
  245.                 if (_dataCount <= 0) {
  246.                     // socket has been closed
  247.                     Close();
  248.                 }
  249.                 else {
  250.                     bProcessRequest = true;
  251.                 }
  252.             }
  253.             catch (Exception e) {
  254.                 CloseOnFatalError(e);
  255.             }
  256.             catch {
  257.                 CloseOnFatalError(new Exception(CoreChannel.GetResourceString("Remoting_nonClsCompliantException")));
  258.             }
  259.            
  260.             if (bProcessRequest) {
  261.                 if (_requestQueue != null)
  262.                     _requestQueue.ProcessNextRequest(this);
  263.                 else
  264.                     ProcessRequestNow();
  265.             }
  266.         }
  267.         // BeginReadMessageCallback
  268.        
  269.         internal void CloseOnFatalError(Exception e)
  270.         {
  271.             try {
  272.                 SendErrorMessageIfPossible(e);
  273.                
  274.                 // Something bad happened, so we should just close everything and
  275.                 // return any buffers to the pool.
  276.                 Close();
  277.             }
  278.             catch {
  279.                 try {
  280.                     Close();
  281.                 }
  282.                 catch {
  283.                     // this is to prevent any weird errors with closing
  284.                     // a socket from showing up as an unhandled exception.
  285.                 }
  286.             }
  287.         }
  288.         // CloseOnFatalError
  289.        
  290.         // Called when the SocketHandler is pulled off the pending request queue.
  291.         internal void ProcessRequestNow()
  292.         {
  293.             try {
  294.                 WaitCallback waitCallback = _dataArrivedCallback;
  295.                 if (waitCallback != null)
  296.                     waitCallback(this);
  297.             }
  298.             catch (Exception e) {
  299.                 CloseOnFatalError(e);
  300.             }
  301.             catch {
  302.                 CloseOnFatalError(new Exception(CoreChannel.GetResourceString("Remoting_nonClsCompliantException")));
  303.             }
  304.         }
  305.         // ProcessRequestNow
  306.        
  307.         internal void RejectRequestNowSinceServerIsBusy()
  308.         {
  309.             CloseOnFatalError(new RemotingException(CoreChannel.GetResourceString("Remoting_ServerIsBusy")));
  310.         }
  311.         // RejectRequestNow
  312.        
  313.        
  314.         public int ReadByte()
  315.         {
  316.             if (Read(_byteBuffer, 0, 1) != -1)
  317.                 return _byteBuffer[0];
  318.             else
  319.                 return -1;
  320.         }
  321.         // ReadByte
  322.         public void WriteByte(byte value, Stream outputStream)
  323.         {
  324.             _byteBuffer[0] = value;
  325.             outputStream.Write(_byteBuffer, 0, 1);
  326.         }
  327.         // WriteUInt16
  328.        
  329.         public UInt16 ReadUInt16()
  330.         {
  331.             Read(_byteBuffer, 0, 2);
  332.            
  333.             return (UInt16)(_byteBuffer[0] & 255 | _byteBuffer[1] << 8);
  334.         }
  335.         // ReadUInt16
  336.         public void WriteUInt16(UInt16 value, Stream outputStream)
  337.         {
  338.             _byteBuffer[0] = (byte)value;
  339.             _byteBuffer[1] = (byte)(value >> 8);
  340.             outputStream.Write(_byteBuffer, 0, 2);
  341.         }
  342.         // WriteUInt16
  343.        
  344.         public int ReadInt32()
  345.         {
  346.             Read(_byteBuffer, 0, 4);
  347.            
  348.             return (int)((_byteBuffer[0] & 255) | _byteBuffer[1] << 8 | _byteBuffer[2] << 16 | _byteBuffer[3] << 24);
  349.         }
  350.         // ReadInt32
  351.         public void WriteInt32(int value, Stream outputStream)
  352.         {
  353.             _byteBuffer[0] = (byte)value;
  354.             _byteBuffer[1] = (byte)(value >> 8);
  355.             _byteBuffer[2] = (byte)(value >> 16);
  356.             _byteBuffer[3] = (byte)(value >> 24);
  357.             outputStream.Write(_byteBuffer, 0, 4);
  358.         }
  359.         // WriteInt32
  360.        
  361.         protected bool ReadAndMatchFourBytes(byte[] buffer)
  362.         {
  363.             InternalRemotingServices.RemotingAssert(buffer.Length == 4, "expecting 4 byte buffer.");
  364.            
  365.             Read(_byteBuffer, 0, 4);
  366.            
  367.             bool bMatch = (_byteBuffer[0] == buffer[0]) && (_byteBuffer[1] == buffer[1]) && (_byteBuffer[2] == buffer[2]) && (_byteBuffer[3] == buffer[3]);
  368.            
  369.             return bMatch;
  370.         }
  371.         // ReadAndMatchFourBytes
  372.        
  373.        
  374.         public int Read(byte[] buffer, int offset, int count)
  375.         {
  376.             int totalBytesRead = 0;
  377.            
  378.             // see if we have buffered data
  379.             if (_dataCount > 0) {
  380.                 // copy minimum of buffered data size and bytes left to read
  381.                 int readCount = Math.Min(_dataCount, count);
  382.                 StreamHelper.BufferCopy(_dataBuffer, _dataOffset, buffer, offset, readCount);
  383.                 _dataCount -= readCount;
  384.                 _dataOffset += readCount;
  385.                 count -= readCount;
  386.                 offset += readCount;
  387.                 totalBytesRead += readCount;
  388.             }
  389.            
  390.             // keep reading (whoever is calling this will make sure that they
  391.             // don't try to read too much).
  392.             while (count > 0) {
  393.                 if (count < 256) {
  394.                     // if count is less than 256 bytes, I will buffer more data
  395.                     // because it's not worth making a socket request for less.
  396.                     BufferMoreData();
  397.                    
  398.                     // copy minimum of buffered data size and bytes left to read
  399.                     int readCount = Math.Min(_dataCount, count);
  400.                     StreamHelper.BufferCopy(_dataBuffer, _dataOffset, buffer, offset, readCount);
  401.                     _dataCount -= readCount;
  402.                     _dataOffset += readCount;
  403.                     count -= readCount;
  404.                     offset += readCount;
  405.                     totalBytesRead += readCount;
  406.                 }
  407.                 else {
  408.                     // just go directly to the socket
  409.                    
  410.                     // the internal buffer is guaranteed to be empty at this point, so just
  411.                     // read directly into the array given
  412.                    
  413.                     int readCount = ReadFromSocket(buffer, offset, count);
  414.                     count -= readCount;
  415.                     offset += readCount;
  416.                     totalBytesRead += readCount;
  417.                 }
  418.             }
  419.            
  420.             return totalBytesRead;
  421.         }
  422.         // Read
  423.        
  424.         // This should only be called when _dataCount is 0.
  425.         private int BufferMoreData()
  426.         {
  427.             InternalRemotingServices.RemotingAssert(_dataCount == 0, "SocketHandler::BufferMoreData called with data still in buffer." + "DataCount=" + _dataCount + "; DataOffset" + _dataOffset);
  428.            
  429.             int bytesRead = ReadFromSocket(_dataBuffer, 0, _dataBufferSize);
  430.            
  431.             _dataOffset = 0;
  432.             _dataCount = bytesRead;
  433.            
  434.             return bytesRead;
  435.         }
  436.         // BufferMoreData
  437.        
  438.         private int ReadFromSocket(byte[] buffer, int offset, int count)
  439.         {
  440.             int bytesRead = NetStream.Read(buffer, offset, count);
  441.             if (bytesRead <= 0) {
  442.                 throw new RemotingException(CoreChannel.GetResourceString("Remoting_Socket_UnderlyingSocketClosed"));
  443.             }
  444.            
  445.             return bytesRead;
  446.         }
  447.         // ReadFromSocket
  448.        
  449.         protected byte[] ReadToByte(byte b)
  450.         {
  451.             return ReadToByte(b, null);
  452.         }
  453.         /// ReadToByte
  454.         protected byte[] ReadToByte(byte b, ValidateByteDelegate validator)
  455.         {
  456.             byte[] readBytes = null;
  457.            
  458.             // start at current position and return byte array consisting of bytes
  459.             // up to where we found the byte.
  460.             if (_dataCount == 0)
  461.                 BufferMoreData();
  462.            
  463.             int dataEnd = _dataOffset + _dataCount;
  464.             // one byte past last valid byte
  465.             int startIndex = _dataOffset;
  466.             // current position
  467.             int endIndex = startIndex;
  468.             // current index
  469.             bool foundByte = false;
  470.             bool bufferEnd;
  471.             while (!foundByte) {
  472.                 InternalRemotingServices.RemotingAssert(endIndex <= dataEnd, "endIndex shouldn't pass dataEnd");
  473.                 bufferEnd = endIndex == dataEnd;
  474.                 foundByte = !bufferEnd && (_dataBuffer[endIndex] == b);
  475.                
  476.                 // validate character if necessary
  477.                 if ((validator != null) && !bufferEnd && !foundByte) {
  478.                     if (!validator(_dataBuffer[endIndex])) {
  479.                         throw new RemotingException(CoreChannel.GetResourceString("Remoting_Http_InvalidDataReceived"));
  480.                     }
  481.                 }
  482.                
  483.                 // we're at the end of the currently buffered data or we've found our byte
  484.                 if (bufferEnd || foundByte) {
  485.                     // store processed byte in the readBytes array
  486.                     int count = endIndex - startIndex;
  487.                     if (readBytes == null) {
  488.                         readBytes = new byte[count];
  489.                         StreamHelper.BufferCopy(_dataBuffer, startIndex, readBytes, 0, count);
  490.                     }
  491.                     else {
  492.                         int oldSize = readBytes.Length;
  493.                         byte[] newBytes = new byte[oldSize + count];
  494.                         StreamHelper.BufferCopy(readBytes, 0, newBytes, 0, oldSize);
  495.                         StreamHelper.BufferCopy(_dataBuffer, startIndex, newBytes, oldSize, count);
  496.                         readBytes = newBytes;
  497.                     }
  498.                    
  499.                     // update data counters
  500.                     _dataOffset += count;
  501.                     _dataCount -= count;
  502.                    
  503.                     if (bufferEnd) {
  504.                         // we still haven't found the byte, so buffer more data
  505.                         // and keep looking.
  506.                         BufferMoreData();
  507.                        
  508.                         // reset indices
  509.                         dataEnd = _dataOffset + _dataCount;
  510.                         // last valid byte
  511.                         startIndex = _dataOffset;
  512.                         // current position
  513.                         endIndex = startIndex;
  514.                         // current index
  515.                     }
  516.                     else if (foundByte) {
  517.                         // skip over the byte that we were looking for
  518.                         _dataOffset += 1;
  519.                         _dataCount -= 1;
  520.                     }
  521.                 }
  522.                 else {
  523.                     // still haven't found character or end of buffer, so advance position
  524.                     endIndex++;
  525.                 }
  526.             }
  527.            
  528.             return readBytes;
  529.         }
  530.         // ReadToByte
  531.        
  532.         protected string ReadToChar(char ch)
  533.         {
  534.             return ReadToChar(ch, null);
  535.         }
  536.         // ReadToChar
  537.         protected string ReadToChar(char ch, ValidateByteDelegate validator)
  538.         {
  539.             byte[] strBytes = ReadToByte((byte)ch, validator);
  540.             if (strBytes == null)
  541.                 return null;
  542.             if (strBytes.Length == 0)
  543.                 return String.Empty;
  544.            
  545.             string str = Encoding.ASCII.GetString(strBytes);
  546.            
  547.             return str;
  548.         }
  549.         // ReadToChar
  550.        
  551.         public string ReadToEndOfLine()
  552.         {
  553.             string str = ReadToChar('\r');
  554.             if (ReadByte() == '\n')
  555.                 return str;
  556.             else
  557.                 return null;
  558.         }
  559.         // ReadToEndOfLine
  560.        
  561.     }
  562.     // SocketHandler
  563.    
  564. }
  565. // namespace System.Runtime.Remoting.Channels

Developer Fusion