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 Thread server_thread = null;
28 TcpServerTransportSink sink;
29 ChannelDataStore channel_data;
30 int _maxConcurrentConnections = 100;
31 ArrayList _activeConnections = new ArrayList();
33 void Init (IServerChannelSinkProvider serverSinkProvider)
35 if (serverSinkProvider == null) {
36 serverSinkProvider = new BinaryServerFormatterSinkProvider ();
39 host = Dns.GetHostByName(Dns.GetHostName()).HostName;
41 string [] uris = null;
44 uris = new String [1];
45 uris [0] = GetChannelUri ();
48 // Gets channel data from the chain of channel providers
50 channel_data = new ChannelDataStore (uris);
51 IServerChannelSinkProvider provider = serverSinkProvider;
\r
52 while (provider != null)
\r
54 provider.GetChannelData(channel_data);
\r
55 provider = provider.Next;
\r
58 // Creates the sink chain that will process all incoming messages
60 IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
\r
61 sink = new TcpServerTransportSink (next_sink);
63 listener = new TcpListener (port);
64 StartListening (null);
67 public TcpServerChannel (int port)
73 public TcpServerChannel (IDictionary properties,
74 IServerChannelSinkProvider serverSinkProvider)
76 port = Int32.Parse ((string)properties ["port"]);
77 Init (serverSinkProvider);
80 public TcpServerChannel (string name, int port,
81 IServerChannelSinkProvider serverSinkProvider)
85 Init (serverSinkProvider);
88 public TcpServerChannel (string name, int port)
95 public object ChannelData
102 public string ChannelName
109 public int ChannelPriority
116 public string GetChannelUri ()
118 return "tcp://" + host + ":" + port;
121 public string[] GetUrlsForUri (string uri)
\r
123 if (!uri.StartsWith ("/")) uri = "/" + uri;
125 string [] chnl_uris = channel_data.ChannelUris;
\r
126 string [] result = new String [chnl_uris.Length];
\r
128 for (int i = 0; i < chnl_uris.Length; i++)
\r
129 result [i] = chnl_uris [i] + uri;
\r
134 public string Parse (string url, out string objectURI)
136 return TcpChannel.ParseChannelUrl (url, out objectURI);
139 void WaitForConnections ()
145 TcpClient client = listener.AcceptTcpClient ();
146 CreateListenerConnection (client);
153 internal void CreateListenerConnection (TcpClient client)
155 lock (_activeConnections)
157 if (_activeConnections.Count >= _maxConcurrentConnections)
158 Monitor.Wait (_activeConnections);
160 if (server_thread == null) return; // Server was stopped while waiting
162 ClientConnection reader = new ClientConnection (this, client, sink);
163 Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
165 thread.IsBackground = true;
166 _activeConnections.Add (thread);
170 internal void ReleaseConnection (Thread thread)
172 lock (_activeConnections)
174 _activeConnections.Remove (thread);
175 Monitor.Pulse (_activeConnections);
179 public void StartListening (object data)
181 if (server_thread == null) {
184 port = ((IPEndPoint)listener.LocalEndpoint).Port;
185 channel_data.ChannelUris = new String [1];
186 channel_data.ChannelUris [0] = GetChannelUri ();
189 server_thread = new Thread (new ThreadStart (WaitForConnections));
190 server_thread.IsBackground = true;
191 server_thread.Start ();
195 public void StopListening (object data)
197 if (server_thread == null) return;
199 lock (_activeConnections)
201 server_thread.Abort ();
202 server_thread = null;
205 foreach (Thread thread in _activeConnections)
208 _activeConnections.Clear();
209 Monitor.PulseAll (_activeConnections);
214 class ClientConnection
217 TcpServerTransportSink _sink;
219 TcpServerChannel _serverChannel;
221 byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
223 public ClientConnection (TcpServerChannel serverChannel, TcpClient client, TcpServerTransportSink sink)
225 _serverChannel = serverChannel;
232 get { return _stream; }
237 get { return _buffer; }
240 public void ProcessMessages()
242 _stream = _client.GetStream();
249 MessageType type = TcpMessageIO.ReceiveMessageType (_stream);
253 case MessageType.MethodMessage:
254 _sink.InternalProcessMessage (this);
257 case MessageType.CancelSignal:
267 _serverChannel.ReleaseConnection (Thread.CurrentThread);