add ISafeSerializationData
[mcs.git] / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Tcp / TcpServerChannel.cs
blobda749054eee1ef9e8922ca102246228973e16269
1 //
2 // System.Runtime.Remoting.Channels.Tcp.TcpServerChannel.cs
3 //
4 // Author: Rodrigo Moya (rodrigo@ximian.com)
5 // Lluis Sanchez Gual (lluis@ideary.com)
6 //
7 // 2002 (C) Copyright, Ximian, Inc.
8 //
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:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
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;
35 using System.Net;
36 using System.Threading;
37 using System.IO;
38 using System.Runtime.Remoting.Channels;
40 namespace System.Runtime.Remoting.Channels.Tcp
42 public class TcpServerChannel : IChannelReceiver, IChannel
44 int port = 0;
45 string name = "tcp";
46 string host = null;
47 int priority = 1;
48 bool supressChannelData = false;
49 bool useIpAddress = true;
51 IPAddress bindAddress = IPAddress.Any;
52 Thread server_thread = null;
53 TcpListener listener;
54 TcpServerTransportSink sink;
55 ChannelDataStore channel_data;
57 RemotingThreadPool threadPool;
59 #if TARGET_JVM
60 private volatile bool stopped = false;
61 #endif
63 void Init (IServerChannelSinkProvider serverSinkProvider)
65 if (serverSinkProvider == null)
67 serverSinkProvider = new BinaryServerFormatterSinkProvider ();
70 if (host == null)
72 if (useIpAddress) {
73 if (!bindAddress.Equals(IPAddress.Any)) host = bindAddress.ToString ();
74 else {
75 IPHostEntry he = Dns.Resolve (Dns.GetHostName());
76 if (he.AddressList.Length == 0) throw new RemotingException ("IP address could not be determined for this host");
77 host = he.AddressList [0].ToString ();
80 else
81 host = Dns.GetHostByName(Dns.GetHostName()).HostName;
84 // Gets channel data from the chain of channel providers
86 channel_data = new ChannelDataStore (null);
87 IServerChannelSinkProvider provider = serverSinkProvider;
88 while (provider != null)
90 provider.GetChannelData(channel_data);
91 provider = provider.Next;
94 // Creates the sink chain that will process all incoming messages
96 IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
97 sink = new TcpServerTransportSink (next_sink);
99 StartListening (null);
102 public TcpServerChannel (int port)
104 this.port = port;
105 Init (null);
108 public TcpServerChannel (IDictionary properties,
109 IServerChannelSinkProvider sinkProvider)
111 foreach(DictionaryEntry property in properties)
113 switch((string)property.Key)
115 case "name":
116 name = property.Value.ToString();
117 break;
118 case "port":
119 port = Convert.ToInt32(property.Value);
120 break;
121 case "priority":
122 priority = Convert.ToInt32(property.Value);
123 break;
124 case "bindTo":
125 bindAddress = IPAddress.Parse((string)property.Value);
126 break;
127 case "rejectRemoteRequests":
128 if(Convert.ToBoolean(properties["rejectRemoteRequests"]))
129 bindAddress = IPAddress.Loopback;
130 break;
131 case "supressChannelData":
132 supressChannelData = Convert.ToBoolean (property.Value);
133 break;
134 case "useIpAddress":
135 useIpAddress = Convert.ToBoolean (property.Value);
136 break;
137 case "machineName":
138 host = property.Value as string;
139 break;
142 Init (sinkProvider);
145 public TcpServerChannel (string name, int port,
146 IServerChannelSinkProvider sinkProvider)
148 this.name = name;
149 this.port = port;
150 Init (sinkProvider);
153 public TcpServerChannel (string name, int port)
155 this.name = name;
156 this.port = port;
157 Init (null);
160 public object ChannelData
162 get {
163 if (supressChannelData) return null;
164 else return channel_data;
168 public string ChannelName
170 get {
171 return name;
175 public int ChannelPriority
177 get {
178 return priority;
182 public string GetChannelUri ()
184 return "tcp://" + host + ":" + port;
187 public virtual string [] GetUrlsForUri (string objectUri)
189 if (!objectUri.StartsWith ("/"))
190 objectUri = "/" + objectUri;
192 string [] chnl_uris = channel_data.ChannelUris;
193 string [] result = new String [chnl_uris.Length];
195 for (int i = 0; i < chnl_uris.Length; i++)
196 result [i] = chnl_uris [i] + objectUri;
198 return result;
201 public string Parse (string url, out string objectURI)
203 return TcpChannel.ParseChannelUrl (url, out objectURI);
206 void WaitForConnections ()
210 #if !TARGET_JVM
211 while(true)
212 #else
213 while(!stopped)
214 #endif
216 Socket socket = listener.AcceptSocket ();
217 ClientConnection reader = new ClientConnection (this, socket, sink);
218 try {
219 if (!threadPool.RunThread (new ThreadStart (reader.ProcessMessages)))
220 socket.Close ();
221 } catch (Exception e)
223 #if DEBUG
224 Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections during start process message: {0} {1}", e.GetType(), e.Message);
225 #endif
229 catch (Exception e)
231 #if DEBUG
232 Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections, stop channel's thread : {0} {1}", e.GetType(), e.Message);
233 #endif
237 public void StartListening (object data)
239 #if TARGET_JVM
240 stopped = false;
241 #endif
242 listener = new TcpListener (bindAddress, port);
243 if (server_thread == null)
245 threadPool = RemotingThreadPool.GetSharedPool ();
246 listener.Start ();
248 if (port == 0)
249 port = ((IPEndPoint)listener.LocalEndpoint).Port;
251 string[] uris = new String [1];
252 uris = new String [1];
253 uris [0] = GetChannelUri ();
254 channel_data.ChannelUris = uris;
256 server_thread = new Thread (new ThreadStart (WaitForConnections));
257 server_thread.IsBackground = true;
258 server_thread.Start ();
262 public void StopListening (object data)
264 #if TARGET_JVM
265 stopped = true;
266 #endif
267 if (server_thread == null) return;
269 #if !TARGET_JVM
270 server_thread.Abort ();
271 #else
272 server_thread.Interrupt ();
273 #endif
274 listener.Stop ();
275 threadPool.Free ();
276 server_thread.Join ();
277 server_thread = null;
281 class ClientConnection
283 static int _count;
284 int _id;
285 Socket _socket;
286 TcpServerTransportSink _sink;
287 Stream _stream;
289 byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
291 public ClientConnection (TcpServerChannel serverChannel, Socket socket, TcpServerTransportSink sink)
293 _socket = socket;
294 _sink = sink;
295 _id = _count++;
298 public Socket Socket {
299 get { return _socket; }
302 public byte[] Buffer
304 get { return _buffer; }
307 public void ProcessMessages()
309 byte[] buffer = new byte[256];
310 NetworkStream ns = new NetworkStream (_socket);
311 _stream = new BufferedStream (ns);
315 bool end = false;
316 while (!end)
318 MessageStatus type = TcpMessageIO.ReceiveMessageStatus (_stream, buffer);
320 switch (type)
322 case MessageStatus.MethodMessage:
323 _sink.InternalProcessMessage (this, _stream);
324 break;
326 case MessageStatus.Unknown:
327 case MessageStatus.CancelSignal:
328 _stream.Flush ();
329 end = true;
330 break;
334 catch (Exception ex)
336 #if DEBUG
337 Console.WriteLine ("The exception was caught during TcpServerChannel.ProcessMessages: {0}, {1}", ex.GetType(), ex.Message);
338 #endif
340 finally
342 try {
343 _stream.Close();
344 _socket.Close ();
346 catch { }
350 public int Id
352 get { return _id; }
355 public IPAddress ClientAddress
357 get {
358 IPEndPoint ep = _socket.RemoteEndPoint as IPEndPoint;
359 if (ep != null) return ep.Address;
360 else return null;