// 2002 (C) Copyright, Ximian, Inc.
//
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
using System.Collections;
using System.Runtime.Remoting.Messaging;
using System.Text.RegularExpressions;
using System.Net;
using System.Threading;
using System.IO;
+using System.Runtime.Remoting.Channels;
namespace System.Runtime.Remoting.Channels.Tcp
{
string host = null;
int priority = 1;
bool supressChannelData = false;
- bool useIpAddress = false;
+ bool useIpAddress = true;
IPAddress bindAddress = IPAddress.Any;
Thread server_thread = null;
TcpListener listener;
TcpServerTransportSink sink;
ChannelDataStore channel_data;
- int _maxConcurrentConnections = 100;
- ArrayList _activeConnections = new ArrayList();
+ RemotingThreadPool threadPool;
+#if TARGET_JVM
+ private volatile bool stopped = false;
+#endif
+
void Init (IServerChannelSinkProvider serverSinkProvider)
{
- if (serverSinkProvider == null) \r
+ if (serverSinkProvider == null)
{
serverSinkProvider = new BinaryServerFormatterSinkProvider ();
}
if (host == null)
{
if (useIpAddress) {
- IPHostEntry he = Dns.Resolve (Dns.GetHostName());
- if (he.AddressList.Length == 0) throw new RemotingException ("IP address could not be determined for this host");
- host = he.AddressList [0].ToString ();
+ if (!bindAddress.Equals(IPAddress.Any)) host = bindAddress.ToString ();
+ else {
+ IPHostEntry he = Dns.Resolve (Dns.GetHostName());
+ if (he.AddressList.Length == 0) throw new RemotingException ("IP address could not be determined for this host");
+ host = he.AddressList [0].ToString ();
+ }
}
else
host = Dns.GetHostByName(Dns.GetHostName()).HostName;
}
- string [] uris = null;
-
- if (port != 0) {
- uris = new String [1];
- uris [0] = GetChannelUri ();
- }
-
// Gets channel data from the chain of channel providers
- channel_data = new ChannelDataStore (uris);
- IServerChannelSinkProvider provider = serverSinkProvider;\r
- while (provider != null)\r
- {\r
- provider.GetChannelData(channel_data);\r
- provider = provider.Next;\r
- }\r
+ channel_data = new ChannelDataStore (null);
+ IServerChannelSinkProvider provider = serverSinkProvider;
+ while (provider != null)
+ {
+ provider.GetChannelData(channel_data);
+ provider = provider.Next;
+ }
// Creates the sink chain that will process all incoming messages
- IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);\r
+ IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
sink = new TcpServerTransportSink (next_sink);
}
IServerChannelSinkProvider serverSinkProvider)
{
foreach(DictionaryEntry property in properties)
- {\r
- switch((string)property.Key)\r
- {\r
- case "port":\r
+ {
+ switch((string)property.Key)
+ {
+ case "name":
+ name = property.Value.ToString();
+ break;
+ case "port":
port = Convert.ToInt32(property.Value);
- break;\r
- case "priority":\r
+ break;
+ case "priority":
priority = Convert.ToInt32(property.Value);
- break;\r
- case "bindTo":\r
+ break;
+ case "bindTo":
bindAddress = IPAddress.Parse((string)property.Value);
- break;\r
- case "rejectRemoteRequests":\r
+ break;
+ case "rejectRemoteRequests":
if(Convert.ToBoolean(properties["rejectRemoteRequests"]))
bindAddress = IPAddress.Loopback;
break;
case "supressChannelData":
supressChannelData = Convert.ToBoolean (property.Value);
- break;\r
+ break;
case "useIpAddress":
useIpAddress = Convert.ToBoolean (property.Value);
break;
case "machineName":
host = property.Value as string;
break;
- }\r
+ }
}
Init (serverSinkProvider);
}
return "tcp://" + host + ":" + port;
}
- public string[] GetUrlsForUri (string uri)\r
- {\r
+ public virtual string[] GetUrlsForUri (string uri)
+ {
if (!uri.StartsWith ("/")) uri = "/" + uri;
-\r
- string [] chnl_uris = channel_data.ChannelUris;\r
- string [] result = new String [chnl_uris.Length];\r
-\r
- for (int i = 0; i < chnl_uris.Length; i++) \r
- result [i] = chnl_uris [i] + uri;\r
- \r
- return result;\r
- }\r
+
+ string [] chnl_uris = channel_data.ChannelUris;
+ string [] result = new String [chnl_uris.Length];
+
+ for (int i = 0; i < chnl_uris.Length; i++)
+ result [i] = chnl_uris [i] + uri;
+
+ return result;
+ }
public string Parse (string url, out string objectURI)
{
{
try
{
- while (true)
+#if !TARGET_JVM
+ while(true)
+#else
+ while(!stopped)
+#endif
{
- TcpClient client = listener.AcceptTcpClient ();
- CreateListenerConnection (client);
+ Socket socket = listener.AcceptSocket ();
+ ClientConnection reader = new ClientConnection (this, socket, sink);
+ try {
+ if (!threadPool.RunThread (new ThreadStart (reader.ProcessMessages)))
+ socket.Close ();
+ } catch (Exception e)
+ {
+#if DEBUG
+ Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections during start process message: {0} {1}", e.GetType(), e.Message);
+#endif
+ }
}
}
- catch
- {}
- }
-
- internal void CreateListenerConnection (TcpClient client)
- {
- lock (_activeConnections)
+ catch (Exception e)
{
- if (_activeConnections.Count >= _maxConcurrentConnections)
- Monitor.Wait (_activeConnections);
-
- if (server_thread == null) return; // Server was stopped while waiting
-
- ClientConnection reader = new ClientConnection (this, client, sink);
- Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
- thread.Start();
- thread.IsBackground = true;
- _activeConnections.Add (thread);
+#if DEBUG
+ Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections, stop channel's thread : {0} {1}", e.GetType(), e.Message);
+#endif
}
}
- internal void ReleaseConnection (Thread thread)
- {
- lock (_activeConnections)
- {
- _activeConnections.Remove (thread);
- Monitor.Pulse (_activeConnections);
- }
- }
-
public void StartListening (object data)
{
+#if TARGET_JVM
+ stopped = false;
+#endif
listener = new TcpListener (bindAddress, port);
- if (server_thread == null) \r
+ if (server_thread == null)
{
+ threadPool = RemotingThreadPool.GetSharedPool ();
listener.Start ();
- if (port == 0) {
+
+ if (port == 0)
port = ((IPEndPoint)listener.LocalEndpoint).Port;
- channel_data.ChannelUris = new String [1];
- channel_data.ChannelUris [0] = GetChannelUri ();
- }
+
+ string[] uris = new String [1];
+ uris = new String [1];
+ uris [0] = GetChannelUri ();
+ channel_data.ChannelUris = uris;
server_thread = new Thread (new ThreadStart (WaitForConnections));
server_thread.IsBackground = true;
public void StopListening (object data)
{
+#if TARGET_JVM
+ stopped = true;
+#endif
if (server_thread == null) return;
-
- lock (_activeConnections)
- {
- server_thread.Abort ();
- server_thread = null;
- listener.Stop ();
-
- foreach (Thread thread in _activeConnections)
- thread.Abort();
-
- _activeConnections.Clear();
- Monitor.PulseAll (_activeConnections);
- }
+
+#if !TARGET_JVM
+ server_thread.Abort ();
+#else
+ server_thread.Interrupt ();
+#endif
+ listener.Stop ();
+ threadPool.Free ();
+ server_thread.Join ();
+ server_thread = null;
}
}
class ClientConnection
{
- TcpClient _client;
+ static int _count;
+ int _id;
+ Socket _socket;
TcpServerTransportSink _sink;
Stream _stream;
- TcpServerChannel _serverChannel;
byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
- public ClientConnection (TcpServerChannel serverChannel, TcpClient client, TcpServerTransportSink sink)
+ public ClientConnection (TcpServerChannel serverChannel, Socket socket, TcpServerTransportSink sink)
{
- _serverChannel = serverChannel;
- _client = client;
+ _socket = socket;
_sink = sink;
+ _id = _count++;
}
- public Stream Stream
- {
- get { return _stream; }
+ public Socket Socket {
+ get { return _socket; }
}
public byte[] Buffer
public void ProcessMessages()
{
- _stream = _client.GetStream();
+ byte[] buffer = new byte[256];
+ NetworkStream ns = new NetworkStream (_socket);
+ _stream = new BufferedStream (ns);
try
{
bool end = false;
while (!end)
{
- MessageStatus type = TcpMessageIO.ReceiveMessageStatus (_stream);
+ MessageStatus type = TcpMessageIO.ReceiveMessageStatus (_stream, buffer);
switch (type)
{
case MessageStatus.MethodMessage:
- _sink.InternalProcessMessage (this);
+ _sink.InternalProcessMessage (this, _stream);
break;
+ case MessageStatus.Unknown:
case MessageStatus.CancelSignal:
end = true;
break;
}
+ _stream.Flush ();
}
}
catch (Exception ex)
{
- Console.WriteLine (ex);
+#if DEBUG
+ Console.WriteLine ("The exception was caught during TcpServerChannel.ProcessMessages: {0}, {1}", ex.GetType(), ex.Message);
+#endif
+ }
+ finally
+ {
+ try {
+ _stream.Close();
+ _socket.Close ();
+ }
+ catch { }
+ }
+ }
+
+ public int Id
+ {
+ get { return _id; }
+ }
+
+ public IPAddress ClientAddress
+ {
+ get {
+ IPEndPoint ep = _socket.RemoteEndPoint as IPEndPoint;
+ if (ep != null) return ep.Address;
+ else return null;
}
-
- _stream.Close();
- _serverChannel.ReleaseConnection (Thread.CurrentThread);
}
}
}