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

  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: TcpServerChannel.cs
  17. //
  18. // Summary: Implements a channel that receives method calls over TCP.
  19. //
  20. //==========================================================================
  21. using System;
  22. using System.Collections;
  23. using System.IO;
  24. using System.Net;
  25. using System.Net.Security;
  26. using System.Net.Sockets;
  27. using System.Runtime.Remoting;
  28. using System.Runtime.Remoting.Channels;
  29. using System.Runtime.Remoting.Messaging;
  30. using System.Security.Cryptography.X509Certificates;
  31. using System.Security.Principal;
  32. using System.Threading;
  33. using System.Runtime.InteropServices;
  34. using System.Globalization;
  35. using System.Security.Permissions;
  36. namespace System.Runtime.Remoting.Channels.Tcp
  37. {
  38.    
  39.     public class TcpServerChannel : IChannelReceiver, ISecurableChannel
  40.     {
  41.         private int _channelPriority = 1;
  42.         // priority of channel (default=1)
  43.         private string _channelName = "tcp";
  44.         // channel name
  45.         private string _machineName = null;
  46.         // machine name
  47.         private int _port = -1;
  48.         // port to listen on
  49.         private ChannelDataStore _channelData = null;
  50.         // channel data
  51.         private string _forcedMachineName = null;
  52.         // an explicitly configured machine name
  53.         private bool _bUseIpAddress = true;
  54.         // by default, we'll use the ip address.
  55.         private IPAddress _bindToAddr = IPAddress.Any;
  56.         // address to bind to.
  57.         private bool _bSuppressChannelData = false;
  58.         // should we hand out null for our channel data
  59.         private bool _impersonate = false;
  60.         // default is no impersonation
  61.         private ProtectionLevel _protectionLevel = ProtectionLevel.EncryptAndSign;
  62.         // default is encrypt and sign is secure is true
  63.         private bool _secure = false;
  64.         // by default authentication is off
  65.         private AsyncCallback _acceptSocketCallback;
  66.         private IAuthorizeRemotingConnection _authorizeRemotingConnection;
  67.         private bool authSet = false;
  68.        
  69.         private IServerChannelSinkProvider _sinkProvider = null;
  70.         private TcpServerTransportSink _transportSink = null;
  71.        
  72.        
  73.         private ExclusiveTcpListener _tcpListener;
  74.         private bool _bExclusiveAddressUse = true;
  75.         private bool _bListening = false;
  76.        
  77.         public TcpServerChannel(int port)
  78.         {
  79.             _port = port;
  80.             SetupMachineName();
  81.             SetupChannel();
  82.         }
  83.         // TcpServerChannel
  84.         public TcpServerChannel(string name, int port)
  85.         {
  86.             _channelName = name;
  87.             _port = port;
  88.             SetupMachineName();
  89.             SetupChannel();
  90.         }
  91.         // TcpServerChannel
  92.         public TcpServerChannel(string name, int port, IServerChannelSinkProvider sinkProvider)
  93.         {
  94.             _channelName = name;
  95.             _port = port;
  96.             _sinkProvider = sinkProvider;
  97.             SetupMachineName();
  98.             SetupChannel();
  99.         }
  100.         // TcpServerChannel
  101.        
  102.         public TcpServerChannel(IDictionary properties, IServerChannelSinkProvider sinkProvider) : this(properties, sinkProvider, null)
  103.         {
  104.         }
  105.        
  106.         public TcpServerChannel(IDictionary properties, IServerChannelSinkProvider sinkProvider, IAuthorizeRemotingConnection authorizeCallback)
  107.         {
  108.             _authorizeRemotingConnection = authorizeCallback;
  109.             if (properties != null) {
  110.                 foreach (DictionaryEntry entry in properties) {
  111.                     switch ((string)entry.Key) {
  112.                         case "name":
  113.                             _channelName = (string)entry.Value;
  114.                             break;
  115.                         case "bindTo":
  116.                             _bindToAddr = IPAddress.Parse((string)entry.Value);
  117.                             break;
  118.                         case "port":
  119.                             _port = Convert.ToInt32(entry.Value, CultureInfo.InvariantCulture);
  120.                             break;
  121.                         case "priority":
  122.                             _channelPriority = Convert.ToInt32(entry.Value, CultureInfo.InvariantCulture);
  123.                             break;
  124.                         case "secure":
  125.                             _secure = Convert.ToBoolean(entry.Value);
  126.                             break;
  127.                         case "impersonate":
  128.                             _impersonate = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
  129.                             authSet = true;
  130.                             break;
  131.                         case "protectionLevel":
  132.                             _protectionLevel = (ProtectionLevel)(entry.Value is ProtectionLevel ? entry.Value : Enum.Parse(typeof(ProtectionLevel), (string)entry.Value, true));
  133.                             authSet = true;
  134.                             break;
  135.                         case "machineName":
  136.                            
  137.                             _forcedMachineName = (string)entry.Value;
  138.                             break;
  139.                         case "rejectRemoteRequests":
  140.                            
  141.                            
  142.                             {
  143.                                 bool bReject = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
  144.                                 if (bReject)
  145.                                     _bindToAddr = IPAddress.Loopback;
  146.                                 break;
  147.                             }
  148.                             break;
  149.                         case "suppressChannelData":
  150.                            
  151.                             _bSuppressChannelData = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
  152.                             break;
  153.                         case "useIpAddress":
  154.                             _bUseIpAddress = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
  155.                             break;
  156.                         case "exclusiveAddressUse":
  157.                             _bExclusiveAddressUse = Convert.ToBoolean(entry.Value, CultureInfo.InvariantCulture);
  158.                             break;
  159.                         case "authorizationModule":
  160.                             _authorizeRemotingConnection = (IAuthorizeRemotingConnection)Activator.CreateInstance(Type.GetType((string)entry.Value, true));
  161.                             break;
  162.                         default:
  163.                             break;
  164.                     }
  165.                 }
  166.                
  167.             }
  168.            
  169.             _sinkProvider = sinkProvider;
  170.             SetupMachineName();
  171.             SetupChannel();
  172.         }
  173.         // TcpServerChannel
  174.        
  175.         //
  176.         // ISecurableChannel implementation
  177.         //
  178.         public bool IsSecured {
  179.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  180.             get { return _secure; }
  181.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  182.             set { _secure = value; }
  183.         }
  184.        
  185.         private void SetupMachineName()
  186.         {
  187.             if (_forcedMachineName != null) {
  188.                 // an explicitly configured machine name was used
  189.                 _machineName = CoreChannel.DecodeMachineName(_forcedMachineName);
  190.             }
  191.             else {
  192.                 if (!_bUseIpAddress)
  193.                     _machineName = CoreChannel.GetMachineName();
  194.                 else {
  195.                     if (_bindToAddr == IPAddress.Any)
  196.                         _machineName = CoreChannel.GetMachineIp();
  197.                     else {
  198.                         _machineName = _bindToAddr.ToString();
  199.                         // Add [] around the ipadress for IPv6
  200.                         if (_bindToAddr.AddressFamily == AddressFamily.InterNetworkV6)
  201.                             _machineName = "[" + _machineName + "]";
  202.                     }
  203.                 }
  204.             }
  205.         }
  206.         // SetupMachineName
  207.        
  208.        
  209.         private void SetupChannel()
  210.         {
  211.             // set channel data
  212.             // (These get changed inside of StartListening(), in the case where the listen
  213.             // port is 0, because we can't determine the port number until after the
  214.             // TcpListener starts.)
  215.            
  216.             if (authSet && !_secure)
  217.                 throw new RemotingException(CoreChannel.GetResourceString("Remoting_Tcp_AuthenticationConfigServer"));
  218.            
  219.             _channelData = new ChannelDataStore(null);
  220.             if (_port > 0) {
  221.                 _channelData.ChannelUris = new string[1];
  222.                 _channelData.ChannelUris[0] = GetChannelUri();
  223.             }
  224.            
  225.             // set default provider (soap formatter) if no provider has been set
  226.             if (_sinkProvider == null)
  227.                 _sinkProvider = CreateDefaultServerProviderChain();
  228.            
  229.             CoreChannel.CollectChannelDataFromServerSinkProviders(_channelData, _sinkProvider);
  230.            
  231.             // construct sink chain
  232.             IServerChannelSink sink = ChannelServices.CreateServerChannelSinkChain(_sinkProvider, this);
  233.             _transportSink = new TcpServerTransportSink(sink, _impersonate);
  234.             // Initialize the accept socket callback
  235.             _acceptSocketCallback = new AsyncCallback(AcceptSocketCallbackHelper);
  236.             if (_port >= 0) {
  237.                 // Open a TCP port and create a thread to start listening
  238.                 _tcpListener = new ExclusiveTcpListener(_bindToAddr, _port);
  239.                 // Wait for thread to spin up
  240.                 StartListening(null);
  241.             }
  242.         }
  243.         // SetupChannel
  244.        
  245.         private IServerChannelSinkProvider CreateDefaultServerProviderChain()
  246.         {
  247.             IServerChannelSinkProvider chain = new BinaryServerFormatterSinkProvider();
  248.             IServerChannelSinkProvider sink = chain;
  249.            
  250.             sink.Next = new SoapServerFormatterSinkProvider();
  251.            
  252.             return chain;
  253.         }
  254.         // CreateDefaultServerProviderChain
  255.        
  256.         //
  257.         // IChannel implementation
  258.         //
  259.        
  260.         public int ChannelPriority {
  261.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  262.             get { return _channelPriority; }
  263.         }
  264.        
  265.         public string ChannelName {
  266.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  267.             get { return _channelName; }
  268.         }
  269.        
  270.         // returns channelURI and places object uri into out parameter
  271.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  272.         public string Parse(string url, out string objectURI)
  273.         {
  274.             return TcpChannelHelper.ParseURL(url, out objectURI);
  275.         }
  276.         // Parse
  277.         //
  278.         // end of IChannel implementation
  279.         //
  280.        
  281.        
  282.         //
  283.         // IChannelReceiver implementation
  284.         //
  285.        
  286.         public object ChannelData {
  287.             [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  288.             get {
  289.                 if (_bSuppressChannelData || !_bListening) {
  290.                     return null;
  291.                 }
  292.                 else {
  293.                     return _channelData;
  294.                 }
  295.             }
  296.         }
  297.         // ChannelData
  298.        
  299.         public string GetChannelUri()
  300.         {
  301.             return "tcp://" + _machineName + ":" + _port;
  302.         }
  303.         // GetChannelUri
  304.        
  305.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  306.         public virtual string[] GetUrlsForUri(string objectUri)
  307.         {
  308.             string[] retVal = new string[1];
  309.            
  310.             if (!objectUri.StartsWith("/", StringComparison.Ordinal))
  311.                 objectUri = "/" + objectUri;
  312.             retVal[0] = GetChannelUri() + objectUri;
  313.            
  314.             return retVal;
  315.         }
  316.         // GetURLsforURI
  317.        
  318.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  319.         public void StartListening(object data)
  320.         {
  321.             InternalRemotingServices.RemotingTrace("HTTPChannel.StartListening");
  322.            
  323.             if (_port >= 0) {
  324.                 _tcpListener.Start(_bExclusiveAddressUse);
  325.                 _bListening = true;
  326.                 // get new port assignment if a port of 0 was used to auto-select a port
  327.                 if (_port == 0) {
  328.                     _port = ((IPEndPoint)_tcpListener.LocalEndpoint).Port;
  329.                     if (_channelData != null) {
  330.                         _channelData.ChannelUris = new string[1];
  331.                         _channelData.ChannelUris[0] = GetChannelUri();
  332.                     }
  333.                 }
  334.                 _tcpListener.BeginAcceptSocket(_acceptSocketCallback, null);
  335.             }
  336.         }
  337.         // StartListening
  338.        
  339.         [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure, Infrastructure = true)]
  340.         public void StopListening(object data)
  341.         {
  342.             InternalRemotingServices.RemotingTrace("HTTPChannel.StopListening");
  343.            
  344.             if (_port > 0) {
  345.                 _bListening = false;
  346.                
  347.                 // Ask the TCP listener to stop listening on the port
  348.                 if (null != _tcpListener) {
  349.                     _tcpListener.Stop();
  350.                 }
  351.             }
  352.         }
  353.         // StopListening
  354.        
  355.         //
  356.         // end of IChannelReceiver implementation
  357.         //
  358.        
  359.         // Helper to invoke the method asynchronously if
  360.         // BeginAccept returns synchronously. In most cases
  361.         // we will simply invoke AcceptSocketCallback
  362.         void AcceptSocketCallbackHelper(IAsyncResult ar)
  363.         {
  364.             if (ar.CompletedSynchronously)
  365.                 ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptSocketCallbackAsync), ar);
  366.             else
  367.                 AcceptSocketCallback(ar);
  368.         }
  369.        
  370.         // This method is used by the helper to convert a sync BeginAccept to async
  371.         void AcceptSocketCallbackAsync(object state)
  372.         {
  373.             AcceptSocketCallback((IAsyncResult)state);
  374.         }
  375.        
  376.         // AcceptSocket method which will invoke the
  377.         // authorization callbacks
  378.         void AcceptSocketCallback(IAsyncResult ar)
  379.         {
  380.             Socket socket = null;
  381.             InternalRemotingServices.RemotingTrace("TCPChannel::Listen - tcpListen.Pending() == true");
  382.             TcpServerSocketHandler streamManager = null;
  383.             bool closeImmediately = true;
  384.             try {
  385.                 //
  386.                 // Wait for an incoming socket
  387.                 // if the listener is still active
  388.                 if (_tcpListener.IsListening)
  389.                     _tcpListener.BeginAcceptSocket(_acceptSocketCallback, null);
  390.                
  391.                 socket = _tcpListener.EndAcceptSocket(ar);
  392.                
  393.                 if (socket == null) {
  394.                     throw new RemotingException(String.Format(CultureInfo.CurrentCulture, CoreChannel.GetResourceString("Remoting_Socket_Accept"), Marshal.GetLastWin32Error().ToString(CultureInfo.CurrentCulture)));
  395.                 }
  396.                
  397.                 if (_authorizeRemotingConnection != null) {
  398.                     bool authorized = _authorizeRemotingConnection.IsConnectingEndPointAuthorized(socket.RemoteEndPoint);
  399.                     if (!authorized)
  400.                         throw new RemotingException(CoreChannel.GetResourceString("Remoting_Tcp_ServerAuthorizationEndpointFailed"));
  401.                 }
  402.                
  403.                 // disable nagle delay
  404.                 socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1);
  405.                 // Set keepalive flag, so that inactive sockets can be cleaned up
  406.                 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
  407.                
  408.                 // set linger option
  409.                 LingerOption lingerOption = new LingerOption(true, 3);
  410.                 socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
  411.                
  412.                 Stream netStream = new SocketStream(socket);
  413.                 streamManager = new TcpServerSocketHandler(socket, CoreChannel.RequestQueue, netStream);
  414.                
  415.                 // If authentication is requested wait for auth request.
  416.                 closeImmediately = false;
  417.                 if (_secure) {
  418.                     throw new NotSupportedException();
  419.                 }
  420.                
  421.                
  422.                
  423.                 streamManager.DataArrivedCallback = new WaitCallback(_transportSink.ServiceRequest);
  424.                 streamManager.BeginReadMessage();
  425.             }
  426.             catch (Exception e) {
  427.                 // Close the socket pre-emptively. We also close the socket if
  428.                 // We need to catch all exceptions if we hit ObjectDisposedException
  429.                 try {
  430.                     if (streamManager != null) {
  431.                         streamManager.SendErrorResponse(e, false);
  432.                     }
  433.                     if (socket != null) {
  434.                         if (closeImmediately)
  435.                             socket.Close(0);
  436.                         else
  437.                             socket.Close();
  438.                     }
  439.                 }
  440.                 catch (Exception) {
  441.                 }
  442.                 if (!_bListening) {
  443.                     // We called Stop() on the tcp listener, so gracefully exit.
  444.                     //bOkToListen = false;
  445.                 }
  446.                 else {
  447.                     // we want the exception to show up as unhandled since this
  448.                     // is an unexpected failure.
  449.                     if (!(e is SocketException)) {
  450.                         //throw;
  451.                     }
  452.                 }
  453.             }
  454.         }
  455.        
  456.        
  457.     }
  458.     // class TcpServerChannel
  459.    
  460.    
  461.     internal class TcpServerTransportSink : IServerChannelSink
  462.     {
  463.         //private const int _defaultChunkSize = 4096;
  464.         private const int s_MaxSize = (2 << 24);
  465.         // Max size of the payload
  466.         // sink state
  467.         private IServerChannelSink _nextSink;
  468.        
  469.         // AuthenticationMode
  470.         private bool _impersonate;
  471.        
  472.         internal TcpServerTransportSink(IServerChannelSink nextSink, bool impersonate)
  473.         {
  474.             _nextSink = nextSink;
  475.             _impersonate = impersonate;
  476.         }
  477.         // TcpServerTransportSink
  478.        
  479.        
  480.         internal void ServiceRequest(object state)
  481.         {
  482.             TcpServerSocketHandler streamManager = (TcpServerSocketHandler)state;
  483.            
  484.             ITransportHeaders headers = streamManager.ReadHeaders();
  485.             Stream requestStream = streamManager.GetRequestStream();
  486.             headers["__CustomErrorsEnabled"] = streamManager.CustomErrorsEnabled();
  487.            
  488.             // process request
  489.             ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
  490.             sinkStack.Push(this, streamManager);
  491.            
  492.             IMessage responseMessage;
  493.             ITransportHeaders responseHeaders;
  494.             Stream responseStream;
  495.            
  496.             ServerProcessing processing;
  497.             // wrap Undo in an outer try block
  498.             try {
  499.                 try {
  500.                     processing = _nextSink.ProcessMessage(sinkStack, null, headers, requestStream, out responseMessage, out responseHeaders, out responseStream);
  501.                 }
  502.                 finally {
  503.                 }
  504.             }
  505.             catch {
  506.                 throw;
  507.             }
  508.            
  509.             // handle response
  510.             switch (processing) {
  511.                 case ServerProcessing.Complete:
  512.                    
  513.                    
  514.                     {
  515.                         // Send the response. Call completed synchronously.
  516.                         sinkStack.Pop(this);
  517.                         streamManager.SendResponse(responseHeaders, responseStream);
  518.                         break;
  519.                     }
  520.                     break;
  521.                 case ServerProcessing.OneWay:
  522.                     // case ServerProcessing.Complete
  523.                    
  524.                     {
  525.                         // No response needed, but the following method will make sure that
  526.                         // we send at least a skeleton reply if the incoming request was
  527.                         // not marked OneWayRequest (client/server metadata could be out of
  528.                         // sync).
  529.                         streamManager.SendResponse(responseHeaders, responseStream);
  530.                         break;
  531.                     }
  532.                     break;
  533.                 case ServerProcessing.Async:
  534.                     // case ServerProcessing.OneWay
  535.                    
  536.                     {
  537.                         sinkStack.StoreAndDispatch(this, streamManager);
  538.                         break;
  539.                     }
  540.                     break;
  541.                 // case ServerProcessing.Async
  542.             }
  543.             // switch (processing)
  544.            
  545.             // async processing will take care if handling this later
  546.             if (processing != ServerProcessing.Async) {
  547.                 if (streamManager.CanServiceAnotherRequest())
  548.                     streamManager.BeginReadMessage();
  549.                 else
  550.                     streamManager.Close();
  551.             }
  552.            
  553.         }
  554.         // ServiceRequest
  555.        
  556.         //
  557.         // IServerChannelSink implementation
  558.         //
  559.        
  560.         public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
  561.         {
  562.             // NOTE: This doesn't have to be implemented because the server transport
  563.             // sink is always first.
  564.             throw new NotSupportedException();
  565.         }
  566.        
  567.        
  568.         public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers, Stream stream)
  569.         {
  570.             TcpServerSocketHandler streamManager = null;
  571.            
  572.             streamManager = (TcpServerSocketHandler)state;
  573.            
  574.             // send the response
  575.             streamManager.SendResponse(headers, stream);
  576.            
  577.             if (streamManager.CanServiceAnotherRequest())
  578.                 streamManager.BeginReadMessage();
  579.             else
  580.                 streamManager.Close();
  581.         }
  582.         // AsyncProcessResponse
  583.        
  584.         public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers)
  585.         {
  586.             // We always want a stream to read from.
  587.             return null;
  588.         }
  589.         // GetResponseStream
  590.        
  591.         public IServerChannelSink NextChannelSink {
  592.             get { return _nextSink; }
  593.         }
  594.        
  595.        
  596.         public IDictionary Properties {
  597.             get { return null; }
  598.         }
  599.         // Properties
  600.         //
  601.         // end of IServerChannelSink implementation
  602.         //
  603.        
  604.        
  605.     }
  606.     // class TcpServerTransportSink
  607.    
  608. }
  609. // namespace System.Runtime.Remoting.Channels.Tcp

Developer Fusion