2 // System.Runtime.Remoting.Channels.Tcp.TcpServerChannel.cs
4 // Author: Rodrigo Moya (rodrigo@ximian.com)
5 // Lluis Sanchez Gual (lluis@ideary.com)
7 // 2002 (C) Copyright, Ximian, Inc.
10 using System.Collections;
11 using System.Runtime.Remoting.Messaging;
12 using System.Text.RegularExpressions;
13 using System.Net.Sockets;
15 using System.Threading;
18 namespace System.Runtime.Remoting.Channels.Tcp
20 public class TcpServerChannel : IChannelReceiver, IChannel
26 bool supressChannelData = false;
27 bool useIpAddress = false;
29 IPAddress bindAddress = IPAddress.Any;
30 Thread server_thread = null;
32 TcpServerTransportSink sink;
33 ChannelDataStore channel_data;
34 int _maxConcurrentConnections = 100;
35 ArrayList _activeConnections = new ArrayList();
38 void Init (IServerChannelSinkProvider serverSinkProvider)
40 if (serverSinkProvider == null)
\r
42 serverSinkProvider = new BinaryServerFormatterSinkProvider ();
48 if (!bindAddress.Equals(IPAddress.Any)) host = bindAddress.ToString ();
50 IPHostEntry he = Dns.Resolve (Dns.GetHostName());
51 if (he.AddressList.Length == 0) throw new RemotingException ("IP address could not be determined for this host");
52 host = he.AddressList [0].ToString ();
56 host = Dns.GetHostByName(Dns.GetHostName()).HostName;
59 // Gets channel data from the chain of channel providers
61 channel_data = new ChannelDataStore (null);
62 IServerChannelSinkProvider provider = serverSinkProvider;
\r
63 while (provider != null)
\r
65 provider.GetChannelData(channel_data);
\r
66 provider = provider.Next;
\r
69 // Creates the sink chain that will process all incoming messages
71 IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
\r
72 sink = new TcpServerTransportSink (next_sink);
75 public TcpServerChannel (int port)
81 public TcpServerChannel (IDictionary properties,
82 IServerChannelSinkProvider serverSinkProvider)
84 foreach(DictionaryEntry property in properties)
86 switch((string)property.Key)
\r
89 port = Convert.ToInt32(property.Value);
92 priority = Convert.ToInt32(property.Value);
95 bindAddress = IPAddress.Parse((string)property.Value);
97 case "rejectRemoteRequests":
\r
98 if(Convert.ToBoolean(properties["rejectRemoteRequests"]))
99 bindAddress = IPAddress.Loopback;
101 case "supressChannelData":
102 supressChannelData = Convert.ToBoolean (property.Value);
105 useIpAddress = Convert.ToBoolean (property.Value);
108 host = property.Value as string;
112 Init (serverSinkProvider);
115 public TcpServerChannel (string name, int port,
116 IServerChannelSinkProvider serverSinkProvider)
120 Init (serverSinkProvider);
123 public TcpServerChannel (string name, int port)
130 public object ChannelData
133 if (supressChannelData) return null;
134 else return channel_data;
138 public string ChannelName
145 public int ChannelPriority
152 public string GetChannelUri ()
154 return "tcp://" + host + ":" + port;
157 public string[] GetUrlsForUri (string uri)
\r
159 if (!uri.StartsWith ("/")) uri = "/" + uri;
161 string [] chnl_uris = channel_data.ChannelUris;
\r
162 string [] result = new String [chnl_uris.Length];
\r
164 for (int i = 0; i < chnl_uris.Length; i++)
\r
165 result [i] = chnl_uris [i] + uri;
\r
170 public string Parse (string url, out string objectURI)
172 return TcpChannel.ParseChannelUrl (url, out objectURI);
175 void WaitForConnections ()
181 TcpClient client = listener.AcceptTcpClient ();
182 CreateListenerConnection (client);
189 internal void CreateListenerConnection (TcpClient client)
191 lock (_activeConnections)
193 if (_activeConnections.Count >= _maxConcurrentConnections)
194 Monitor.Wait (_activeConnections);
196 if (server_thread == null) return; // Server was stopped while waiting
198 ClientConnection reader = new ClientConnection (this, client, sink);
199 Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
201 thread.IsBackground = true;
202 _activeConnections.Add (thread);
206 internal void ReleaseConnection (Thread thread)
208 lock (_activeConnections)
210 _activeConnections.Remove (thread);
211 Monitor.Pulse (_activeConnections);
215 public void StartListening (object data)
217 listener = new TcpListener (bindAddress, port);
218 if (server_thread == null)
\r
223 port = ((IPEndPoint)listener.LocalEndpoint).Port;
225 string[] uris = new String [1];
226 uris = new String [1];
227 uris [0] = GetChannelUri ();
228 channel_data.ChannelUris = uris;
230 server_thread = new Thread (new ThreadStart (WaitForConnections));
231 server_thread.IsBackground = true;
232 server_thread.Start ();
236 public void StopListening (object data)
238 if (server_thread == null) return;
240 lock (_activeConnections)
242 server_thread.Abort ();
243 server_thread = null;
246 foreach (Thread thread in _activeConnections)
249 _activeConnections.Clear();
250 Monitor.PulseAll (_activeConnections);
255 class ClientConnection
258 TcpServerTransportSink _sink;
260 TcpServerChannel _serverChannel;
262 byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
264 public ClientConnection (TcpServerChannel serverChannel, TcpClient client, TcpServerTransportSink sink)
266 _serverChannel = serverChannel;
273 get { return _stream; }
278 get { return _buffer; }
281 public void ProcessMessages()
283 _stream = _client.GetStream();
290 MessageStatus type = TcpMessageIO.ReceiveMessageStatus (_stream);
294 case MessageStatus.MethodMessage:
295 _sink.InternalProcessMessage (this);
298 case MessageStatus.CancelSignal:
306 // Console.WriteLine (ex);
310 _serverChannel.ReleaseConnection (Thread.CurrentThread);