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
;
39 namespace System
.Runtime
.Remoting
.Channels
.Tcp
41 public class TcpServerChannel
: IChannelReceiver
, IChannel
47 bool supressChannelData
= false;
48 bool useIpAddress
= false;
50 IPAddress bindAddress
= IPAddress
.Any
;
51 Thread server_thread
= null;
53 TcpServerTransportSink sink
;
54 ChannelDataStore channel_data
;
55 int _maxConcurrentConnections
= 100;
56 ArrayList _activeConnections
= new ArrayList();
59 void Init (IServerChannelSinkProvider serverSinkProvider
)
61 if (serverSinkProvider
== null)
63 serverSinkProvider
= new BinaryServerFormatterSinkProvider ();
69 if (!bindAddress
.Equals(IPAddress
.Any
)) host
= bindAddress
.ToString ();
71 IPHostEntry he
= Dns
.Resolve (Dns
.GetHostName());
72 if (he
.AddressList
.Length
== 0) throw new RemotingException ("IP address could not be determined for this host");
73 host
= he
.AddressList
[0].ToString ();
77 host
= Dns
.GetHostByName(Dns
.GetHostName()).HostName
;
80 // Gets channel data from the chain of channel providers
82 channel_data
= new ChannelDataStore (null);
83 IServerChannelSinkProvider provider
= serverSinkProvider
;
84 while (provider
!= null)
86 provider
.GetChannelData(channel_data
);
87 provider
= provider
.Next
;
90 // Creates the sink chain that will process all incoming messages
92 IServerChannelSink next_sink
= ChannelServices
.CreateServerChannelSinkChain (serverSinkProvider
, this);
93 sink
= new TcpServerTransportSink (next_sink
);
96 public TcpServerChannel (int port
)
102 public TcpServerChannel (IDictionary properties
,
103 IServerChannelSinkProvider serverSinkProvider
)
105 foreach(DictionaryEntry property
in properties
)
107 switch((string)property
.Key
)
110 name
= property
.Value
.ToString();
113 port
= Convert
.ToInt32(property
.Value
);
116 priority
= Convert
.ToInt32(property
.Value
);
119 bindAddress
= IPAddress
.Parse((string)property
.Value
);
121 case "rejectRemoteRequests":
122 if(Convert
.ToBoolean(properties
["rejectRemoteRequests"]))
123 bindAddress
= IPAddress
.Loopback
;
125 case "supressChannelData":
126 supressChannelData
= Convert
.ToBoolean (property
.Value
);
129 useIpAddress
= Convert
.ToBoolean (property
.Value
);
132 host
= property
.Value
as string;
136 Init (serverSinkProvider
);
139 public TcpServerChannel (string name
, int port
,
140 IServerChannelSinkProvider serverSinkProvider
)
144 Init (serverSinkProvider
);
147 public TcpServerChannel (string name
, int port
)
154 public object ChannelData
157 if (supressChannelData
) return null;
158 else return channel_data
;
162 public string ChannelName
169 public int ChannelPriority
176 public string GetChannelUri ()
178 return "tcp://" + host
+ ":" + port
;
181 public string[] GetUrlsForUri (string uri
)
183 if (!uri
.StartsWith ("/")) uri
= "/" + uri
;
185 string [] chnl_uris
= channel_data
.ChannelUris
;
186 string [] result
= new String
[chnl_uris
.Length
];
188 for (int i
= 0; i
< chnl_uris
.Length
; i
++)
189 result
[i
] = chnl_uris
[i
] + uri
;
194 public string Parse (string url
, out string objectURI
)
196 return TcpChannel
.ParseChannelUrl (url
, out objectURI
);
199 void WaitForConnections ()
205 TcpClient client
= listener
.AcceptTcpClient ();
206 CreateListenerConnection (client
);
213 internal void CreateListenerConnection (TcpClient client
)
215 lock (_activeConnections
)
217 if (_activeConnections
.Count
>= _maxConcurrentConnections
)
218 Monitor
.Wait (_activeConnections
);
220 if (server_thread
== null) return; // Server was stopped while waiting
222 ClientConnection reader
= new ClientConnection (this, client
, sink
);
223 Thread thread
= new Thread (new ThreadStart (reader
.ProcessMessages
));
225 thread
.IsBackground
= true;
226 _activeConnections
.Add (thread
);
230 internal void ReleaseConnection (Thread thread
)
232 lock (_activeConnections
)
234 _activeConnections
.Remove (thread
);
235 Monitor
.Pulse (_activeConnections
);
239 public void StartListening (object data
)
241 listener
= new TcpListener (bindAddress
, port
);
242 if (server_thread
== null)
247 port
= ((IPEndPoint
)listener
.LocalEndpoint
).Port
;
249 string[] uris
= new String
[1];
250 uris
= new String
[1];
251 uris
[0] = GetChannelUri ();
252 channel_data
.ChannelUris
= uris
;
254 server_thread
= new Thread (new ThreadStart (WaitForConnections
));
255 server_thread
.IsBackground
= true;
256 server_thread
.Start ();
260 public void StopListening (object data
)
262 if (server_thread
== null) return;
264 lock (_activeConnections
)
266 server_thread
.Abort ();
267 server_thread
= null;
270 foreach (Thread thread
in _activeConnections
)
273 _activeConnections
.Clear();
274 Monitor
.PulseAll (_activeConnections
);
279 class ClientConnection
282 TcpServerTransportSink _sink
;
284 TcpServerChannel _serverChannel
;
286 byte[] _buffer
= new byte[TcpMessageIO
.DefaultStreamBufferSize
];
288 public ClientConnection (TcpServerChannel serverChannel
, TcpClient client
, TcpServerTransportSink sink
)
290 _serverChannel
= serverChannel
;
297 get { return _stream; }
302 get { return _buffer; }
305 public void ProcessMessages()
307 _stream
= _client
.GetStream();
314 MessageStatus type
= TcpMessageIO
.ReceiveMessageStatus (_stream
);
318 case MessageStatus
.MethodMessage
:
319 _sink
.InternalProcessMessage (this);
322 case MessageStatus
.CancelSignal
:
330 // Console.WriteLine (ex);
335 _serverChannel
.ReleaseConnection (Thread
.CurrentThread
);