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 IPAddress bindAddress = IPAddress.Any;
27 Thread server_thread = null;
29 TcpServerTransportSink sink;
30 ChannelDataStore channel_data;
31 int _maxConcurrentConnections = 100;
32 ArrayList _activeConnections = new ArrayList();
34 void Init (IServerChannelSinkProvider serverSinkProvider)
36 if (serverSinkProvider == null)
\r
38 serverSinkProvider = new BinaryServerFormatterSinkProvider ();
41 host = Dns.GetHostByName(Dns.GetHostName()).HostName;
43 string [] uris = null;
46 uris = new String [1];
47 uris [0] = GetChannelUri ();
50 // Gets channel data from the chain of channel providers
52 channel_data = new ChannelDataStore (uris);
53 IServerChannelSinkProvider provider = serverSinkProvider;
\r
54 while (provider != null)
\r
56 provider.GetChannelData(channel_data);
\r
57 provider = provider.Next;
\r
60 // Creates the sink chain that will process all incoming messages
62 IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
\r
63 sink = new TcpServerTransportSink (next_sink);
65 listener = new TcpListener(bindAddress, port);
66 StartListening (null);
69 public TcpServerChannel (int port)
75 public TcpServerChannel (IDictionary properties,
76 IServerChannelSinkProvider serverSinkProvider)
78 foreach(DictionaryEntry property in properties)
80 switch((string)property.Key)
\r
83 port = Convert.ToInt32(property.Value);
86 priority = Convert.ToInt32(property.Value);
89 bindAddress = IPAddress.Parse((string)property.Value);
91 case "rejectRemoteRequests":
\r
92 if(Convert.ToBoolean(properties["rejectRemoteRequests"]))
93 bindAddress = IPAddress.Loopback;
97 Init (serverSinkProvider);
100 public TcpServerChannel (string name, int port,
101 IServerChannelSinkProvider serverSinkProvider)
105 Init (serverSinkProvider);
108 public TcpServerChannel (string name, int port)
115 public object ChannelData
122 public string ChannelName
129 public int ChannelPriority
136 public string GetChannelUri ()
138 return "tcp://" + host + ":" + port;
141 public string[] GetUrlsForUri (string uri)
\r
143 if (!uri.StartsWith ("/")) uri = "/" + uri;
145 string [] chnl_uris = channel_data.ChannelUris;
\r
146 string [] result = new String [chnl_uris.Length];
\r
148 for (int i = 0; i < chnl_uris.Length; i++)
\r
149 result [i] = chnl_uris [i] + uri;
\r
154 public string Parse (string url, out string objectURI)
156 return TcpChannel.ParseChannelUrl (url, out objectURI);
159 void WaitForConnections ()
165 TcpClient client = listener.AcceptTcpClient ();
166 CreateListenerConnection (client);
173 internal void CreateListenerConnection (TcpClient client)
175 lock (_activeConnections)
177 if (_activeConnections.Count >= _maxConcurrentConnections)
178 Monitor.Wait (_activeConnections);
180 if (server_thread == null) return; // Server was stopped while waiting
182 ClientConnection reader = new ClientConnection (this, client, sink);
183 Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
185 thread.IsBackground = true;
186 _activeConnections.Add (thread);
190 internal void ReleaseConnection (Thread thread)
192 lock (_activeConnections)
194 _activeConnections.Remove (thread);
195 Monitor.Pulse (_activeConnections);
199 public void StartListening (object data)
201 if (server_thread == null)
\r
205 port = ((IPEndPoint)listener.LocalEndpoint).Port;
206 channel_data.ChannelUris = new String [1];
207 channel_data.ChannelUris [0] = GetChannelUri ();
210 server_thread = new Thread (new ThreadStart (WaitForConnections));
211 server_thread.IsBackground = true;
212 server_thread.Start ();
216 public void StopListening (object data)
218 if (server_thread == null) return;
220 lock (_activeConnections)
222 server_thread.Abort ();
223 server_thread = null;
226 foreach (Thread thread in _activeConnections)
229 _activeConnections.Clear();
230 Monitor.PulseAll (_activeConnections);
235 class ClientConnection
238 TcpServerTransportSink _sink;
240 TcpServerChannel _serverChannel;
242 byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
244 public ClientConnection (TcpServerChannel serverChannel, TcpClient client, TcpServerTransportSink sink)
246 _serverChannel = serverChannel;
253 get { return _stream; }
258 get { return _buffer; }
261 public void ProcessMessages()
263 _stream = _client.GetStream();
270 MessageStatus type = TcpMessageIO.ReceiveMessageStatus (_stream);
274 case MessageStatus.MethodMessage:
275 _sink.InternalProcessMessage (this);
278 case MessageStatus.CancelSignal:
288 _serverChannel.ReleaseConnection (Thread.CurrentThread);