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.
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Runtime.Remoting.Messaging;
33 using System.Text.RegularExpressions;
34 using System.Net.Sockets;
36 using System.Threading;
38 using System.Runtime.Remoting.Channels;
40 namespace System.Runtime.Remoting.Channels.Tcp
42 public class TcpServerChannel : IChannelReceiver, IChannel
48 bool supressChannelData = false;
49 bool useIpAddress = true;
51 IPAddress bindAddress = IPAddress.Any;
52 Thread server_thread = null;
54 TcpServerTransportSink sink;
55 ChannelDataStore channel_data;
57 RemotingThreadPool threadPool;
60 void Init (IServerChannelSinkProvider serverSinkProvider)
62 if (serverSinkProvider == null)
64 serverSinkProvider = new BinaryServerFormatterSinkProvider ();
70 if (!bindAddress.Equals(IPAddress.Any)) host = bindAddress.ToString ();
72 IPHostEntry he = Dns.Resolve (Dns.GetHostName());
73 if (he.AddressList.Length == 0) throw new RemotingException ("IP address could not be determined for this host");
74 host = he.AddressList [0].ToString ();
78 host = Dns.GetHostByName(Dns.GetHostName()).HostName;
81 // Gets channel data from the chain of channel providers
83 channel_data = new ChannelDataStore (null);
84 IServerChannelSinkProvider provider = serverSinkProvider;
85 while (provider != null)
87 provider.GetChannelData(channel_data);
88 provider = provider.Next;
91 // Creates the sink chain that will process all incoming messages
93 IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
94 sink = new TcpServerTransportSink (next_sink);
96 StartListening (null);
99 public TcpServerChannel (int port)
105 public TcpServerChannel (IDictionary properties,
106 IServerChannelSinkProvider sinkProvider)
108 foreach(DictionaryEntry property in properties)
110 switch((string)property.Key)
113 name = property.Value.ToString();
116 port = Convert.ToInt32(property.Value);
119 priority = Convert.ToInt32(property.Value);
122 bindAddress = IPAddress.Parse((string)property.Value);
124 case "rejectRemoteRequests":
125 if(Convert.ToBoolean(properties["rejectRemoteRequests"]))
126 bindAddress = IPAddress.Loopback;
128 case "supressChannelData":
129 supressChannelData = Convert.ToBoolean (property.Value);
132 useIpAddress = Convert.ToBoolean (property.Value);
135 host = property.Value as string;
142 public TcpServerChannel (string name, int port,
143 IServerChannelSinkProvider sinkProvider)
150 public TcpServerChannel (string name, int port)
157 public object ChannelData
160 if (supressChannelData) return null;
161 else return channel_data;
165 public string ChannelName
172 public int ChannelPriority
179 public string GetChannelUri ()
181 return "tcp://" + host + ":" + port;
184 public virtual string [] GetUrlsForUri (string objectUri)
186 if (!objectUri.StartsWith ("/"))
187 objectUri = "/" + objectUri;
189 string [] chnl_uris = channel_data.ChannelUris;
190 string [] result = new String [chnl_uris.Length];
192 for (int i = 0; i < chnl_uris.Length; i++)
193 result [i] = chnl_uris [i] + objectUri;
198 public string Parse (string url, out string objectURI)
200 return TcpChannel.ParseChannelUrl (url, out objectURI);
203 void WaitForConnections ()
209 Socket socket = listener.AcceptSocket ();
210 ClientConnection reader = new ClientConnection (this, socket, sink);
212 if (!threadPool.RunThread (new ThreadStart (reader.ProcessMessages)))
214 } catch (Exception e)
217 Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections during start process message: {0} {1}", e.GetType(), e.Message);
225 Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections, stop channel's thread : {0} {1}", e.GetType(), e.Message);
230 public void StartListening (object data)
232 listener = new TcpListener (bindAddress, port);
233 if (server_thread == null)
235 threadPool = RemotingThreadPool.GetSharedPool ();
239 port = ((IPEndPoint)listener.LocalEndpoint).Port;
241 string[] uris = new String [1];
242 uris = new String [1];
243 uris [0] = GetChannelUri ();
244 channel_data.ChannelUris = uris;
246 server_thread = new Thread (new ThreadStart (WaitForConnections));
247 server_thread.IsBackground = true;
248 server_thread.Start ();
252 public void StopListening (object data)
254 if (server_thread == null) return;
256 server_thread.Abort ();
259 server_thread.Join ();
260 server_thread = null;
264 class ClientConnection
269 TcpServerTransportSink _sink;
272 byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
274 public ClientConnection (TcpServerChannel serverChannel, Socket socket, TcpServerTransportSink sink)
281 public Socket Socket {
282 get { return _socket; }
287 get { return _buffer; }
290 public void ProcessMessages()
292 byte[] buffer = new byte[256];
293 NetworkStream ns = new NetworkStream (_socket);
294 _stream = new BufferedStream (ns);
301 MessageStatus type = TcpMessageIO.ReceiveMessageStatus (_stream, buffer);
305 case MessageStatus.MethodMessage:
306 _sink.InternalProcessMessage (this, _stream);
309 case MessageStatus.Unknown:
310 case MessageStatus.CancelSignal:
320 Console.WriteLine ("The exception was caught during TcpServerChannel.ProcessMessages: {0}, {1}", ex.GetType(), ex.Message);
338 public IPAddress ClientAddress
341 IPEndPoint ep = _socket.RemoteEndPoint as IPEndPoint;
342 if (ep != null) return ep.Address;