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 private volatile bool stopped
= false;
63 void Init (IServerChannelSinkProvider serverSinkProvider
)
65 if (serverSinkProvider
== null)
67 serverSinkProvider
= new BinaryServerFormatterSinkProvider ();
73 if (!bindAddress
.Equals(IPAddress
.Any
)) host
= bindAddress
.ToString ();
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 ();
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
)
108 public TcpServerChannel (IDictionary properties
,
109 IServerChannelSinkProvider sinkProvider
)
111 foreach(DictionaryEntry property
in properties
)
113 switch((string)property
.Key
)
116 name
= property
.Value
.ToString();
119 port
= Convert
.ToInt32(property
.Value
);
122 priority
= Convert
.ToInt32(property
.Value
);
125 bindAddress
= IPAddress
.Parse((string)property
.Value
);
127 case "rejectRemoteRequests":
128 if(Convert
.ToBoolean(properties
["rejectRemoteRequests"]))
129 bindAddress
= IPAddress
.Loopback
;
131 case "supressChannelData":
132 supressChannelData
= Convert
.ToBoolean (property
.Value
);
135 useIpAddress
= Convert
.ToBoolean (property
.Value
);
138 host
= property
.Value
as string;
145 public TcpServerChannel (string name
, int port
,
146 IServerChannelSinkProvider sinkProvider
)
153 public TcpServerChannel (string name
, int port
)
160 public object ChannelData
163 if (supressChannelData
) return null;
164 else return channel_data
;
168 public string ChannelName
175 public int ChannelPriority
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
;
201 public string Parse (string url
, out string objectURI
)
203 return TcpChannel
.ParseChannelUrl (url
, out objectURI
);
206 void WaitForConnections ()
216 Socket socket
= listener
.AcceptSocket ();
217 ClientConnection reader
= new ClientConnection (this, socket
, sink
);
219 if (!threadPool
.RunThread (new ThreadStart (reader
.ProcessMessages
)))
221 } catch (Exception e
)
224 Console
.WriteLine("Exception caught in TcpServerChannel.WaitForConnections during start process message: {0} {1}", e
.GetType(), e
.Message
);
232 Console
.WriteLine("Exception caught in TcpServerChannel.WaitForConnections, stop channel's thread : {0} {1}", e
.GetType(), e
.Message
);
237 public void StartListening (object data
)
242 listener
= new TcpListener (bindAddress
, port
);
243 if (server_thread
== null)
245 threadPool
= RemotingThreadPool
.GetSharedPool ();
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
)
267 if (server_thread
== null) return;
270 server_thread
.Abort ();
272 server_thread
.Interrupt ();
276 server_thread
.Join ();
277 server_thread
= null;
281 class ClientConnection
286 TcpServerTransportSink _sink
;
289 byte[] _buffer
= new byte[TcpMessageIO
.DefaultStreamBufferSize
];
291 public ClientConnection (TcpServerChannel serverChannel
, Socket socket
, TcpServerTransportSink sink
)
298 public Socket Socket
{
299 get { return _socket; }
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
);
318 MessageStatus type
= TcpMessageIO
.ReceiveMessageStatus (_stream
, buffer
);
322 case MessageStatus
.MethodMessage
:
323 _sink
.InternalProcessMessage (this, _stream
);
326 case MessageStatus
.Unknown
:
327 case MessageStatus
.CancelSignal
:
337 Console
.WriteLine ("The exception was caught during TcpServerChannel.ProcessMessages: {0}, {1}", ex
.GetType(), ex
.Message
);
355 public IPAddress ClientAddress
358 IPEndPoint ep
= _socket
.RemoteEndPoint
as IPEndPoint
;
359 if (ep
!= null) return ep
.Address
;