Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
2008-09-18 Robert Jordan <robertj@gmx.net>
* TcpConnectionPool.cs: Set NoDelay on both profiles.
2008-09-18 Zoltan Varga <vargaz@gmail.com>
* TcpConnectionPool.cs: Set the NoDelay flag on the socket to avoid
excessive waiting by the tcp stack. Fixes #416462.
2008-09-17 Jeffrey Stedfast <fejj@novell.com>
* TcpChannel.cs (ParseTcpURL): If given "tcp://", don't set host
to "", leave it as null.
* TcpClientChannel.cs (TcpClientChannel): Use the default
SinkProviders if the sinkProvider argument is null.
* TcpChannel.cs (ParseTcpURL): TcpClientTransportSink needs the
host component, so extract that info into its own string as well.
2008-09-12 Jeffrey Stedfast <fejj@novell.com>
Fix for bug #320298
* TcpClientTransportSink.cs: Updated for change to
TcpChannel.ParseTcpURL(). We now need to do our own integer
conversion/validation of the port.
* TcpChannel.cs (ParseTcpURL): We need to match the
protocol ("tcp") case-insensitively. The objectURI is supposed to
include the leading '/' character. Also, we need to ignore invalid
port designators since Microsoft's .NET implementation of
TcpChannel.Parse() doesn't seem to care that they are valid.
2008-08-09 Gert Driesen <drieseng@users.sourceforge.net>
* TcpChannel.cs: Fixed argument names to match MS.
* TcpServerChannel.cs: Fixed argument names to match MS.
2008-06-18 Robert Jordan <robertj@gmx.net>
* TcpMessageIO.cs: Handle zero length streams. Fixes #398783.
2008-01-25 Zoltan Varga <vargaz@gmail.com>
* TcpChannel.cs (Init): Handle properties == null.
* TcpClientChannel.cs (.ctor): Ditto. Fixes #355905.
2006-01-09 Robert Jordan <robertj@gmx.net>
* TcpServerChannel.cs (ProcessMessages): Flush the stream only when
necessary (TcpServerTransportSink.InternalProcessMessage does it anyway),
otherwise pending OneWay & async messages are lost.
* TcpMessageIO.cs (SendMessageStream): Mark OneWay messages as such.
Fixes MS.NET interoperability.
* TcpClientTransportSink.cs (AsyncProcessRequest):
Use the new TcpMessageIO.SendMessageStream overload to mark OneWay
requests. Fixes bug #80406.
2007-01-08 Lluis Sanchez Gual <lluis@novell.com>
* TcpChannel.cs, TcpServerChannel.cs: Moved StartListening call to
the constructor of TcpServerChannel.
2006-12-18 Lluis Sanchez Gual <lluis@novell.com>
* TcpChannel.cs: The remoting infrastructure does not call
StartListening() anymore, so it has to be called by the channel.
2006-09-15 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerTransportSink.cs, TcpServerChannel.cs:
When sending an async call response, don't use the original request
stream because it may have been used by another call.
2006-05-31 Gert Driesen <drieseng@users.sourceforge.net>
* TcpClientChannel.cs: Marked CreateMessageSink virtual.
* TcpServerChannel.cs: Marked GetUrlsForUri virtual.
2006-05-31 Gert Driesen <drieseng@users.sourceforge.net>
* TcpClientChannel.cs: Set eol-style to native.
* TcpChannel.cs: Fixed line endings. Set eol-style to native.
* TcpServerTransportSink.cs: Fixed line endings. Set eol-style to
native.
* TcpConnectionPool.cs: Fixed line endings. Set eol-style to CRLF.
* TcpClientTransportSinkProvider.cs: Fixed line endings. Set eol-style
to native.
* TcpMessageIO.cs: Set eol-style to native.
* TcpServerChannel.cs: Fixed line endings. Set eol-style to native.
* TcpClientTransportSink.cs: Fixed line endings. Set eol-style to
native.
2005-11-08 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerChannel.cs: Fix null ref exception.
2005-11-06 Svetlana Zholkovsky <svetlanaz@mainsoft.com>
* TcpServerChannel.cs, TcpConnectionPool.cs: only TARGET_JVM changes
2005-07-25 Lluis Sanchez Gual <lluis@novell.com>
* TcpChannel.cs: Don't create a server channel when the
default constructor is used. Fixes bug #75626.
2005-05-31 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerTransportSink.cs: Remove the channel uri from the
received uri.
2005-05-31 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerChannel.cs: Use IP address in object uris by default.
Fixes bug #54234. Removed unused field.
* TcpClientTransportSink.cs: Fix warning.
2005-05-18 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerChannel.cs: In StopListening, wait for the server thread
to stop before returning. This fixes bug #74962.
2005-01-25 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerTransportSink.cs: Set IPAddress and ConnectionId
transport headers. This fixes bug #71423.
* TcpServerChannel.cs: Use Socket instead of TcpClient, so we can
easily get the IP address of the client. Added properties in
ClientConnection to get the IP address and the connection id.
2005-01-21 Lluis Sanchez Gual <lluis@novell.com>
* TcpMessageIO.cs: Added a buffer parameter to ReceiveMessageStatus,
to avoid creating unneded buffers.
* TcpServerChannel.cs, TcpClientTransportSink.cs: Use new buffer
parameter in ReceiveMessageStatus.
2005-01-14 Lluis Sanchez Gual <lluis@novell.com>
* TcpConnectionPool.cs: Don't limit client connections.
This fixes bug #70700. Create connections from outside the pool lock.
* TcpMessageIO.cs: Throw real exceptions when errors occur.
* TcpServerChannel.cs: Use the new RemotingThreadPool to manage threads.
This also fixes bug #70700.
2004-12-17 Lluis Sanchez Gual <lluis@novell.com>
* TcpMessageIO.cs: Removed some more WriteByte calls.
* TcpClientTransportSink.cs: Flush the net stream after writing
a message.
2004-12-10 Lluis Sanchez Gual <lluis@novell.com>
* TcpChannel.cs: Don't use regular expressions to parse the url, it's
too slow.
* TcpMessageIO.cs: Read byte chunks using the new StreamRead method,
which won't block if the connection is closed.
* TcpServerChannel.cs: Flush the stream after writing the response.
Wrap the close call in a try/catch (some bytes can be left in the
buffered stream if a connection is suddently closed, and it will fail
when trying to flush them).
2004-12-09 Lluis Sanchez Gual <lluis@novell.com>
* TcpConnectionPool.cs: Access the socket stream through a
BufferedStream.
* TcpMessageIO.cs: Avoid ReadByte().
* TcpServerChannel.cs: Access the socket stream through a
BufferedStream. Abort the connection if an unknown message is received.
All this fixes performance bug #70337.
2004-10-22 Lluis Sanchez Gual <lluis@ximian.com>
* TcpClientChannel.cs: In CreateMessageSink, process the remote channel
data if the provided url does not have the expected format. This fixes
a regression from the fix for bug #66768 and fixes #68669.
2004-07-15 Lluis Sanchez Gual <lluis@novell.com>
* TcpServerChannel.cs: Set channel name from the provided properties.
This fixes bug #61592.
2004-05-13 Lluis Sanchez Gual <lluis@ximian.com>
* TcpChannel.cs: Made Init private.
* TcpClientTransportSink.cs, TcpClientTransportSinkProvider.cs,
TcpServerTransportSink.cs: Made internal.
2004-04-16 Lluis Sanchez Gual <lluis@ximian.com>
* TcpClientChannel.cs: Initialize the sink provider in the default
constructor.
2004-03-04 Lluis Sanchez Gual <lluis@ximian.com>
* TcpServerChannel.cs: In the ProcessMessages() loop, moved the closing of
the stream to the finally block, so it is called if the thread is aborted.
2004-02-27 Lluis Sanchez Gual <lluis@ximian.com>
* TcpClientTransportSink.cs: Set the RequestUri transport header before
sending the request.
2004-02-23 Lluis Sanchez Gual <lluis@ximian.com>
* TcpClientTransportSink.cs: Release the connection after sending an
OneWay call. This fixes bug #54671.
2003-12-23 Lluis Sanchez Gual <lluis@ximian.com>
* TcpServerChannel.cs: If useIpAddress and bindAddress are both specified,
set bindAddress as the host address for the client.
2003-12-19 Lluis Sanchez Gual <lluis@ximian.com>
* TcpServerChannel.cs: Fixes in channel initialization.
2003-12-12 Lluis Sanchez Gual <lluis@ximian.com>
* TcpChannel.cs: Added null check.
2003-11-16 Lluis Sanchez Gual <lluis@ximian.com>
* TcpClientChannel.cs: Added support for name and priority properties.
* TcpServerChannel.cs: Added support for priority, bindTo, useIpAddress,
machineName and supressChannelData properties.
* TcpChannel.cs, TcpServerTransportSink.cs: Formatting change.
2003-11-13 Lluis Sanchez Gual <lluis@ximian.com>
* TcpChannel.cs: take into account name and priority properties.
2003-11-12 Lluis Sanchez Gual <lluis@ximian.com>
* TcpServerChannel.cs: Remove listener initialization and StartListening
call from constructor. It is called now by the remoting framework.
* TcpConnectionPool.cs: Removed fixme.
Older log entries can be found in the System.Runtime.Remoting ChangeLog.

View File

@@ -0,0 +1,193 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpChannel.cs
//
// Author: Rodrigo Moya (rodrigo@ximian.com)
// Lluis Sanchez Gual (lluis@ideary.com)
//
// 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;
namespace System.Runtime.Remoting.Channels.Tcp
{
public class TcpChannel : IChannelReceiver, IChannel, IChannelSender
{
private TcpClientChannel _clientChannel;
private TcpServerChannel _serverChannel;
private string _name = "tcp";
private int _priority = 1;
public TcpChannel ()
{
Init (new Hashtable(), null, null);
}
public TcpChannel (int port)
{
Hashtable ht = new Hashtable();
ht ["port"] = port.ToString();
Init (ht, null, null);
}
void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
{
_clientChannel = new TcpClientChannel (properties,clientSink);
if (properties != null) {
if(properties["port"] != null)
_serverChannel = new TcpServerChannel(properties, serverSink);
object val = properties ["name"];
if (val != null)
_name = val as string;
val = properties ["priority"];
if (val != null)
_priority = Convert.ToInt32 (val);
}
}
public TcpChannel (IDictionary properties,
IClientChannelSinkProvider clientSinkProvider,
IServerChannelSinkProvider serverSinkProvider)
{
Init (properties, clientSinkProvider, serverSinkProvider);
}
public IMessageSink CreateMessageSink(string url, object remoteChannelData, out string objectURI)
{
return _clientChannel.CreateMessageSink(url,
remoteChannelData, out objectURI);
}
public string ChannelName {
get { return _name; }
}
public int ChannelPriority {
get { return _priority; }
}
public void StartListening (object data)
{
if (_serverChannel != null)
_serverChannel.StartListening (data);
}
public void StopListening (object data)
{
if (_serverChannel != null)
_serverChannel.StopListening(data);
TcpConnectionPool.Shutdown ();
}
public string [] GetUrlsForUri (string objectURI)
{
if (_serverChannel != null)
return _serverChannel.GetUrlsForUri (objectURI);
return null;
}
public object ChannelData {
get {
if (_serverChannel != null)
return _serverChannel.ChannelData;
return null;
}
}
public string Parse (string url, out string objectURI)
{
return TcpChannel.ParseChannelUrl (url, out objectURI);
}
internal static string ParseChannelUrl (string url, out string objectURI)
{
if (url == null)
throw new ArgumentNullException ("url");
string host, port;
return ParseTcpURL (url, out host, out port, out objectURI);
}
internal static string ParseTcpURL (string url, out string host, out string port, out string objectURI)
{
// format: "tcp://host:port/path/to/object"
objectURI = null;
host = null;
port = null;
// url needs to be at least "tcp:"
if (url.Length < 4 || url[3] != ':' ||
(url[0] != 'T' && url[0] != 't') ||
(url[1] != 'C' && url[1] != 'c') ||
(url[2] != 'P' && url[2] != 'p'))
return null;
// "tcp:" is acceptable
if (url.Length == 4)
return url;
// must be of the form "tcp://"
if (url.Length <= 5 || url[4] != '/' || url[5] != '/')
return null;
// "tcp://" is acceptable
if (url.Length == 6)
return url;
int i;
for (i = 6; i < url.Length; i++) {
if (url[i] == ':' || url[i] == '/')
break;
}
host = url.Substring (6, i - 6);
if (i + 1 < url.Length && url[i] == ':') {
int start = i + 1;
for (i++; i < url.Length; i++) {
if (url[i] == '/')
break;
}
if (i > start)
port = url.Substring (start, i - start);
}
if (i >= url.Length || url[i] != '/')
return url;
objectURI = url.Substring (i);
return url.Substring (0, i);
}
}
}

View File

@@ -0,0 +1,142 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpClientChannel.cs
//
// Author: Dietmar Maurer (dietmar@ximian.com)
// Lluis Sanchez Gual (lluis@ideary.com)
//
// 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.IO;
using System.Net.Sockets;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels;
using System.Threading;
namespace System.Runtime.Remoting.Channels.Tcp
{
public class TcpClientChannel : IChannelSender, IChannel
{
int priority = 1;
string name = "tcp";
IClientChannelSinkProvider _sinkProvider;
public TcpClientChannel ()
{
_sinkProvider = new BinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new TcpClientTransportSinkProvider ();
}
public TcpClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
{
if (properties != null) {
object val = properties ["name"];
if (val != null) name = val as string;
val = properties ["priority"];
if (val != null) priority = Convert.ToInt32 (val);
}
if (sinkProvider != null)
{
_sinkProvider = sinkProvider;
// add the tcp provider at the end of the chain
IClientChannelSinkProvider prov = sinkProvider;
while (prov.Next != null) prov = prov.Next;
prov.Next = new TcpClientTransportSinkProvider ();
// Note: a default formatter is added only when
// no sink providers are specified in the config file.
}
else
{
_sinkProvider = new BinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new TcpClientTransportSinkProvider ();
}
}
public TcpClientChannel (string name, IClientChannelSinkProvider sinkProvider)
{
this.name = name;
if (sinkProvider != null) {
_sinkProvider = sinkProvider;
// add the tcp provider at the end of the chain
IClientChannelSinkProvider prov = sinkProvider;
while (prov.Next != null)
prov = prov.Next;
prov.Next = new TcpClientTransportSinkProvider ();
} else {
_sinkProvider = new BinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new TcpClientTransportSinkProvider ();
}
}
public string ChannelName
{
get {
return name;
}
}
public int ChannelPriority
{
get {
return priority;
}
}
public virtual IMessageSink CreateMessageSink (string url,
object remoteChannelData,
out string objectURI)
{
if (url != null && Parse (url, out objectURI) != null)
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
if (remoteChannelData != null) {
IChannelDataStore ds = remoteChannelData as IChannelDataStore;
if (ds != null && ds.ChannelUris.Length > 0)
url = ds.ChannelUris [0];
else {
objectURI = null;
return null;
}
}
if (Parse (url, out objectURI) == null)
return null;
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
}
public string Parse (string url, out string objectURI)
{
return TcpChannel.ParseChannelUrl (url, out objectURI);
}
}
}

View File

@@ -0,0 +1,205 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.cs
//
// Author: Dietmar Maurer (dietmar@ximian.com)
// Lluis Sanchez Gual (lluis@ideary.com)
//
// 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;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.Collections;
using System.IO;
using System.Threading;
namespace System.Runtime.Remoting.Channels.Tcp
{
internal class TcpClientTransportSink : IClientChannelSink
{
string _host;
int _port;
public TcpClientTransportSink (string url)
{
string objectUri;
string port;
TcpChannel.ParseTcpURL (url, out _host, out port, out objectUri);
try {
if (port != null)
_port = Convert.ToInt32 (port);
else
_port = 0;
} catch {
_host = null;
_port = -1;
}
}
public IDictionary Properties
{
get
{
return null;
}
}
public IClientChannelSink NextChannelSink
{
get
{
// we are the last one
return null;
}
}
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
ITransportHeaders headers, Stream requestStream)
{
TcpConnection connection = null;
bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
try
{
if (headers == null) headers = new TransportHeaders();
headers [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
// Sends the stream using a connection from the pool
// and creates a WorkItem that will wait for the
// response of the server
connection = TcpConnectionPool.GetConnection (_host, _port);
TcpMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer, isOneWay);
connection.Stream.Flush ();
if (!isOneWay)
{
sinkStack.Push (this, connection);
ThreadPool.QueueUserWorkItem (new WaitCallback(data => {
try {
ReadAsyncTcpMessage (data);
} catch {}
}), sinkStack);
}
else
connection.Release();
}
catch
{
if (connection != null) connection.Release();
if (!isOneWay) throw;
}
}
private void ReadAsyncTcpMessage(object data)
{
// This method is called by a new thread to asynchronously
// read the response to a request
// The stack was provided as state data in QueueUserWorkItem
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
// The first sink in the stack is this sink. Pop it and
// get the status data, which is the TcpConnection used to send
// the request
TcpConnection connection = (TcpConnection)stack.Pop(this);
try
{
ITransportHeaders responseHeaders;
// Read the response, blocking if necessary
MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
if (status != MessageStatus.MethodMessage)
throw new RemotingException ("Unknown response message from server");
Stream responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
// Free the connection, so it can be reused
connection.Release();
connection = null;
// Ok, proceed with the other sinks
stack.AsyncProcessResponse (responseHeaders, responseStream);
}
catch
{
if (connection != null) connection.Release();
throw;
}
}
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
object state, ITransportHeaders headers,
Stream stream)
{
// Should never be called
throw new NotSupportedException();
}
public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
{
return null;
}
public void ProcessMessage (IMessage msg,
ITransportHeaders requestHeaders,
Stream requestStream,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
TcpConnection connection = null;
try
{
if (requestHeaders == null) requestHeaders = new TransportHeaders();
requestHeaders [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
// Sends the message
connection = TcpConnectionPool.GetConnection (_host, _port);
TcpMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
connection.Stream.Flush ();
// Reads the response
MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
if (status != MessageStatus.MethodMessage)
throw new RemotingException ("Unknown response message from server");
responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
}
finally
{
if (connection != null)
connection.Release();
}
}
}
}

View File

@@ -0,0 +1,62 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSinkProvider.cs
//
// Author: Dietmar Maurer (dietmar@ximian.com)
// Lluis Sanchez (lsg@ctv.es)
//
// 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;
using System.Runtime.Remoting.Channels;
namespace System.Runtime.Remoting.Channels.Tcp
{
internal class TcpClientTransportSinkProvider : IClientChannelSinkProvider
{
public TcpClientTransportSinkProvider ()
{
// what should we do here ?
}
public IClientChannelSinkProvider Next
{
get
{
return null;
}
set
{
// ignore, we are always the last in the chain
}
}
public IClientChannelSink CreateSink (IChannelSender channel, string url,
object remoteChannelData)
{
return new TcpClientTransportSink (url);
}
}
}

View File

@@ -0,0 +1,323 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpConnectionPool.cs
//
// Author: Lluis Sanchez Gual (lluis@ideary.com)
//
// 2002 (C) Lluis Sanchez Gual
//
//
// 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;
using System.Collections;
using System.Threading;
using System.IO;
using System.Net.Sockets;
namespace System.Runtime.Remoting.Channels.Tcp
{
// This is a pool of Tcp connections. Connections requested
// by the TCP channel are pooled after their use, and can
// be reused later. Connections are automaticaly closed
// if not used after some time, specified in KeepAliveSeconds.
// The number of allowed open connections can also be specified
// in MaxOpenConnections. The limit is per host.
// If a thread requests a connection and the limit has been
// reached, the thread is suspended until one is released.
internal class TcpConnectionPool
{
// Table of pools. There is a HostConnectionPool
// instance for each host
static Hashtable _pools = new Hashtable();
static int _maxOpenConnections = int.MaxValue;
static int _keepAliveSeconds = 15;
static Thread _poolThread;
static TcpConnectionPool()
{
// This thread will close unused connections
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
_poolThread.IsBackground = true;
_poolThread.Start();
}
public static void Shutdown ()
{
#if !TARGET_JVM
if (_poolThread != null)
_poolThread.Abort();
#endif
}
public static int MaxOpenConnections
{
get { return _maxOpenConnections; }
set
{
if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero");
_maxOpenConnections = value;
}
}
public static int KeepAliveSeconds
{
get { return _keepAliveSeconds; }
set { _keepAliveSeconds = value; }
}
public static TcpConnection GetConnection (string host, int port)
{
HostConnectionPool hostPool;
lock (_pools)
{
string key = host + ":" + port;
hostPool = (HostConnectionPool) _pools[key];
if (hostPool == null)
{
hostPool = new HostConnectionPool(host, port);
_pools[key] = hostPool;
}
}
return hostPool.GetConnection();
}
private static void ConnectionCollector ()
{
while (true)
{
Thread.Sleep(3000);
lock (_pools)
{
ICollection values = _pools.Values;
foreach (HostConnectionPool pool in values)
pool.PurgeConnections();
}
}
}
}
internal class ReusableTcpClient : TcpClient
{
public ReusableTcpClient (string host, int port): base (host, port)
{
// Avoid excessive waiting for data by the tcp stack in linux.
// We can't safely use SetSocketOption for both runtimes because
// it would break 2.0 TcpClient's property cache.
#if NET_2_0
Client.NoDelay = true;
#else
Client.SetSocketOption (SocketOptionLevel.Tcp,
SocketOptionName.NoDelay, 1);
#endif
}
public bool IsAlive
{
get
{
// This Poll will return true if there is data pending to
// be read. It prob. means that a client object using this
// connection got an exception and did not finish to read
// the data. It can also mean that the connection has been
// closed in the server. In both cases, the connection cannot
// be reused.
return !Client.Poll (0, SelectMode.SelectRead);
}
}
}
internal class TcpConnection
{
DateTime _controlTime;
Stream _stream;
ReusableTcpClient _client;
HostConnectionPool _pool;
byte[] _buffer;
public TcpConnection (HostConnectionPool pool, ReusableTcpClient client)
{
_pool = pool;
_client = client;
_stream = new BufferedStream (client.GetStream());
_controlTime = DateTime.Now;
_buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
}
public Stream Stream
{
get { return _stream; }
}
public DateTime ControlTime
{
get { return _controlTime; }
set { _controlTime = value; }
}
public bool IsAlive
{
get { return _client.IsAlive; }
}
// This is a "thread safe" buffer that can be used by
// TcpClientTransportSink to read or send data to the stream.
// The buffer is "thread safe" since only one thread can
// use a connection at a given time.
public byte[] Buffer
{
get { return _buffer; }
}
// Returns the connection to the pool
public void Release()
{
_pool.ReleaseConnection (this);
}
public void Close()
{
_client.Close();
}
}
internal class HostConnectionPool
{
ArrayList _pool = new ArrayList();
int _activeConnections = 0;
string _host;
int _port;
public HostConnectionPool (string host, int port)
{
_host = host;
_port = port;
}
public TcpConnection GetConnection ()
{
TcpConnection connection = null;
lock (_pool)
{
do
{
if (_pool.Count > 0)
{
// There are available connections
connection = (TcpConnection)_pool[_pool.Count - 1];
_pool.RemoveAt(_pool.Count - 1);
if (!connection.IsAlive) {
CancelConnection (connection);
connection = null;
continue;
}
}
if (connection == null && _activeConnections < TcpConnectionPool.MaxOpenConnections)
{
// No connections available, but the max connections
// has not been reached yet, so a new one can be created
// Create the connection outside the lock
break;
}
// No available connections in the pool
// Wait for somewone to release one.
if (connection == null)
{
Monitor.Wait(_pool);
}
}
while (connection == null);
}
if (connection == null)
return CreateConnection ();
else
return connection;
}
private TcpConnection CreateConnection()
{
try
{
ReusableTcpClient client = new ReusableTcpClient(_host, _port);
TcpConnection entry = new TcpConnection(this, client);
_activeConnections++;
return entry;
}
catch (Exception ex)
{
throw new RemotingException (ex.Message);
}
}
public void ReleaseConnection (TcpConnection entry)
{
lock (_pool)
{
entry.ControlTime = DateTime.Now; // Initialize timeout
_pool.Add (entry);
Monitor.Pulse (_pool);
}
}
private void CancelConnection(TcpConnection entry)
{
try
{
entry.Stream.Close();
_activeConnections--;
}
catch
{
}
}
public void PurgeConnections()
{
lock (_pool)
{
for (int n=0; n < _pool.Count; n++)
{
TcpConnection entry = (TcpConnection)_pool[n];
if ( (DateTime.Now - entry.ControlTime).TotalSeconds > TcpConnectionPool.KeepAliveSeconds)
{
CancelConnection (entry);
_pool.RemoveAt(n);
n--;
}
}
}
}
}
}

View File

@@ -0,0 +1,298 @@
// System.Runtime.Remoting.Channels.Tcp.TcpMessageIO.cs
//
// Author: Lluis Sanchez Gual (lluis@ideary.com)
//
// (C) 2002 Lluis Sanchez Gual
//
// 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;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using System.IO;
using System.Text;
using System.Net.Sockets;
namespace System.Runtime.Remoting.Channels.Tcp
{
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
internal class TcpMessageIO
{
static byte[][] _msgHeaders =
{
new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
new byte[] { 255, 255, 255, 255, 255, 255 }
};
public static int DefaultStreamBufferSize = 1000;
// Identifies an incoming message
public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer)
{
try {
StreamRead (networkStream, buffer, 6);
} catch (Exception ex) {
throw new RemotingException ("Tcp transport error.", ex);
}
try
{
bool[] isOnTrack = new bool[_msgHeaders.Length];
bool atLeastOneOnTrack = true;
int i = 0;
while (atLeastOneOnTrack)
{
atLeastOneOnTrack = false;
byte c = buffer [i];
for (int n = 0; n<_msgHeaders.Length; n++)
{
if (i > 0 && !isOnTrack[n]) continue;
isOnTrack[n] = (c == _msgHeaders[n][i]);
if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
}
i++;
}
return MessageStatus.Unknown;
}
catch (Exception ex) {
throw new RemotingException ("Tcp transport error.", ex);
}
}
static bool StreamRead (Stream networkStream, byte[] buffer, int count)
{
int nr = 0;
do {
int pr = networkStream.Read (buffer, nr, count - nr);
if (pr == 0)
throw new RemotingException ("Connection closed");
nr += pr;
} while (nr < count);
return true;
}
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
{
SendMessageStream (networkStream, data, requestHeaders, buffer, false);
}
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer, bool isOneWay)
{
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
// Writes the message start header
byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
// Writes the header tag
// 0x0000 - request stream
// 0x0001 - OneWay request stream
// 0x0002 - response stream
if(requestHeaders[CommonTransportKeys.RequestUri]!=null) {
buffer [0] = isOneWay ? (byte) 1 : (byte) 0;
}
else {
buffer[0] = (byte) 2;
}
buffer [1] = (byte) 0 ;
// Writes ID
buffer [2] = (byte) 0;
// Writes assemblyID????
buffer [3] = (byte) 0;
// Writes the length of the stream being sent (not including the headers)
int num = (int)data.Length;
buffer [4] = (byte) num;
buffer [5] = (byte) (num >> 8);
buffer [6] = (byte) (num >> 16);
buffer [7] = (byte) (num >> 24);
networkStream.Write(buffer, 0, 8);
// Writes the message headers
SendHeaders (networkStream, requestHeaders, buffer);
if (data.Length == 0)
return;
// Writes the stream
if (data is MemoryStream)
{
// The copy of the stream can be optimized. The internal
// buffer of MemoryStream can be used.
MemoryStream memStream = (MemoryStream)data;
networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
}
else
{
int nread = data.Read (buffer, 0, buffer.Length);
while (nread > 0)
{
networkStream.Write (buffer, 0, nread);
nread = data.Read (buffer, 0, buffer.Length);
}
}
}
static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 };
static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 };
static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 };
static byte[] msgHeaderTerminator = new byte[] { 0, 0 };
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
{
// Writes the headers as a sequence of strings
if (networkStream != null)
{
IEnumerator e = requestHeaders.GetEnumerator();
while (e.MoveNext())
{
DictionaryEntry hdr = (DictionaryEntry)e.Current;
switch (hdr.Key.ToString())
{
case CommonTransportKeys.RequestUri:
networkStream.Write (msgUriTransportKey, 0, 4);
break;
case "Content-Type":
networkStream.Write (msgContentTypeTransportKey, 0, 4);
break;
default:
networkStream.Write (msgDefaultTransportKey, 0, 3);
SendString (networkStream, hdr.Key.ToString(), buffer);
networkStream.WriteByte (1);
break;
}
SendString (networkStream, hdr.Value.ToString(), buffer);
}
}
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
}
public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
{
StreamRead (networkStream, buffer, 2);
byte headerType = buffer [0];
TransportHeaders headers = new TransportHeaders ();
while (headerType != 0)
{
string key;
StreamRead (networkStream, buffer, 1); // byte 1
switch (headerType)
{
case 4: key = CommonTransportKeys.RequestUri; break;
case 6: key = "Content-Type"; break;
case 1: key = ReceiveString (networkStream, buffer); break;
default: throw new NotSupportedException ("Unknown header code: " + headerType);
}
StreamRead (networkStream, buffer, 1); // byte 1
headers[key] = ReceiveString (networkStream, buffer);
StreamRead (networkStream, buffer, 2);
headerType = buffer [0];
}
return headers;
}
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
{
headers = null;
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
// +
// Gets the length of the data stream
StreamRead (networkStream, buffer, 8);
int byteCount = (buffer [4] | (buffer [5] << 8) |
(buffer [6] << 16) | (buffer [7] << 24));
// Reads the headers
headers = ReceiveHeaders (networkStream, buffer);
if (byteCount > 0) {
byte[] resultBuffer = new byte[byteCount];
StreamRead (networkStream, resultBuffer, byteCount);
return new MemoryStream (resultBuffer);
} else {
return new MemoryStream ();
}
}
private static void SendString (Stream networkStream, string str, byte[] buffer)
{
// Allocates a buffer. Use the internal buffer if it is
// big enough. If not, create a new one.
int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
if (maxBytes > buffer.Length)
buffer = new byte[maxBytes];
int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
// store number of bytes (not number of chars!)
buffer [0] = (byte) num;
buffer [1] = (byte) (num >> 8);
buffer [2] = (byte) (num >> 16);
buffer [3] = (byte) (num >> 24);
// Write the string bytes
networkStream.Write (buffer, 0, num + 4);
}
private static string ReceiveString (Stream networkStream, byte[] buffer)
{
StreamRead (networkStream, buffer, 4);
// Reads the number of bytes (not chars!)
int byteCount = (buffer [0] | (buffer [1] << 8) |
(buffer [2] << 16) | (buffer [3] << 24));
if (byteCount == 0) return string.Empty;
// Allocates a buffer of the correct size. Use the
// internal buffer if it is big enough
if (byteCount > buffer.Length)
buffer = new byte[byteCount];
// Reads the string
StreamRead (networkStream, buffer, byteCount);
char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
return new string (chars);
}
}
}

View File

@@ -0,0 +1,364 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpServerChannel.cs
//
// Author: Rodrigo Moya (rodrigo@ximian.com)
// Lluis Sanchez Gual (lluis@ideary.com)
//
// 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.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using System.Runtime.Remoting.Channels;
namespace System.Runtime.Remoting.Channels.Tcp
{
public class TcpServerChannel : IChannelReceiver, IChannel
{
int port = 0;
string name = "tcp";
string host = null;
int priority = 1;
bool supressChannelData = false;
bool useIpAddress = true;
IPAddress bindAddress = IPAddress.Any;
Thread server_thread = null;
TcpListener listener;
TcpServerTransportSink sink;
ChannelDataStore channel_data;
RemotingThreadPool threadPool;
#if TARGET_JVM
private volatile bool stopped = false;
#endif
void Init (IServerChannelSinkProvider serverSinkProvider)
{
if (serverSinkProvider == null)
{
serverSinkProvider = new BinaryServerFormatterSinkProvider ();
}
if (host == null)
{
if (useIpAddress) {
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;
}
// Gets channel data from the chain of channel providers
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);
sink = new TcpServerTransportSink (next_sink);
StartListening (null);
}
public TcpServerChannel (int port)
{
this.port = port;
Init (null);
}
public TcpServerChannel (IDictionary properties,
IServerChannelSinkProvider sinkProvider)
{
foreach(DictionaryEntry property in properties)
{
switch((string)property.Key)
{
case "name":
name = property.Value.ToString();
break;
case "port":
port = Convert.ToInt32(property.Value);
break;
case "priority":
priority = Convert.ToInt32(property.Value);
break;
case "bindTo":
bindAddress = IPAddress.Parse((string)property.Value);
break;
case "rejectRemoteRequests":
if(Convert.ToBoolean(properties["rejectRemoteRequests"]))
bindAddress = IPAddress.Loopback;
break;
case "supressChannelData":
supressChannelData = Convert.ToBoolean (property.Value);
break;
case "useIpAddress":
useIpAddress = Convert.ToBoolean (property.Value);
break;
case "machineName":
host = property.Value as string;
break;
}
}
Init (sinkProvider);
}
public TcpServerChannel (string name, int port,
IServerChannelSinkProvider sinkProvider)
{
this.name = name;
this.port = port;
Init (sinkProvider);
}
public TcpServerChannel (string name, int port)
{
this.name = name;
this.port = port;
Init (null);
}
public object ChannelData
{
get {
if (supressChannelData) return null;
else return channel_data;
}
}
public string ChannelName
{
get {
return name;
}
}
public int ChannelPriority
{
get {
return priority;
}
}
public string GetChannelUri ()
{
return "tcp://" + host + ":" + port;
}
public virtual string [] GetUrlsForUri (string objectUri)
{
if (!objectUri.StartsWith ("/"))
objectUri = "/" + objectUri;
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] + objectUri;
return result;
}
public string Parse (string url, out string objectURI)
{
return TcpChannel.ParseChannelUrl (url, out objectURI);
}
void WaitForConnections ()
{
try
{
#if !TARGET_JVM
while(true)
#else
while(!stopped)
#endif
{
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 (Exception e)
{
#if DEBUG
Console.WriteLine("Exception caught in TcpServerChannel.WaitForConnections, stop channel's thread : {0} {1}", e.GetType(), e.Message);
#endif
}
}
public void StartListening (object data)
{
#if TARGET_JVM
stopped = false;
#endif
listener = new TcpListener (bindAddress, port);
if (server_thread == null)
{
threadPool = RemotingThreadPool.GetSharedPool ();
listener.Start ();
if (port == 0)
port = ((IPEndPoint)listener.LocalEndpoint).Port;
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;
server_thread.Start ();
}
}
public void StopListening (object data)
{
#if TARGET_JVM
stopped = true;
#endif
if (server_thread == null) return;
#if !TARGET_JVM
server_thread.Abort ();
#else
server_thread.Interrupt ();
#endif
listener.Stop ();
threadPool.Free ();
server_thread.Join ();
server_thread = null;
}
}
class ClientConnection
{
static int _count;
int _id;
Socket _socket;
TcpServerTransportSink _sink;
Stream _stream;
byte[] _buffer = new byte[TcpMessageIO.DefaultStreamBufferSize];
public ClientConnection (TcpServerChannel serverChannel, Socket socket, TcpServerTransportSink sink)
{
_socket = socket;
_sink = sink;
_id = _count++;
}
public Socket Socket {
get { return _socket; }
}
public byte[] Buffer
{
get { return _buffer; }
}
public void ProcessMessages()
{
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, buffer);
switch (type)
{
case MessageStatus.MethodMessage:
_sink.InternalProcessMessage (this, _stream);
break;
case MessageStatus.Unknown:
case MessageStatus.CancelSignal:
_stream.Flush ();
end = true;
break;
}
}
}
#if DEBUG
catch (Exception ex)
{
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;
}
}
}
}

View File

@@ -0,0 +1,137 @@
//
// System.Runtime.Remoting.Channels.Tcp.TcpServerTransportSink.cs
//
// Author: Rodrigo Moya (rodrigo@ximian.com)
// Lluis Sanchez Gual (lsg@ctv.es)
//
// 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;
using System.Collections;
using System.Runtime.Remoting.Messaging;
using System.Net.Sockets;
using System.IO;
namespace System.Runtime.Remoting.Channels.Tcp
{
internal class TcpServerTransportSink : IServerChannelSink, IChannelSinkBase
{
IServerChannelSink next_sink;
public TcpServerTransportSink (IServerChannelSink next)
{
next_sink = next;
}
public IServerChannelSink NextChannelSink
{
get
{
return next_sink;
}
}
public IDictionary Properties
{
get
{
if (next_sink != null) return next_sink.Properties;
else return null;
}
}
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
IMessage msg, ITransportHeaders headers, Stream responseStream)
{
ClientConnection connection = (ClientConnection)state;
NetworkStream ns = new NetworkStream (connection.Socket);
TcpMessageIO.SendMessageStream (ns, responseStream, headers, connection.Buffer);
ns.Flush ();
ns.Close ();
}
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
IMessage msg, ITransportHeaders headers)
{
return null;
}
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
IMessage requestMsg,
ITransportHeaders requestHeaders,
Stream requestStream,
out IMessage responseMsg,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
// this is the first sink, and TcpServerChannel does not call it.
throw new NotSupportedException ();
}
internal void InternalProcessMessage (ClientConnection connection, Stream stream)
{
// Reads the headers and the request stream
Stream requestStream;
ITransportHeaders requestHeaders;
requestStream = TcpMessageIO.ReceiveMessageStream (stream, out requestHeaders, connection.Buffer);
requestHeaders [CommonTransportKeys.IPAddress] = connection.ClientAddress;
requestHeaders [CommonTransportKeys.ConnectionId] = connection.Id;
string uri = (string) requestHeaders [CommonTransportKeys.RequestUri];
TcpChannel.ParseChannelUrl (uri, out uri);
if (uri != null)
requestHeaders [CommonTransportKeys.RequestUri] = uri;
// Pushes the connection object together with the sink. This information
// will be used for sending the response in an async call.
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
sinkStack.Push(this, connection);
ITransportHeaders responseHeaders;
Stream responseStream;
IMessage responseMsg;
ServerProcessing proc = next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
switch (proc)
{
case ServerProcessing.Complete:
TcpMessageIO.SendMessageStream (stream, responseStream, responseHeaders, connection.Buffer);
stream.Flush ();
break;
case ServerProcessing.Async:
case ServerProcessing.OneWay:
break;
}
}
}
}