--- /dev/null
+Example Channel Implementation:
+===============================
+
+This Channel is just used as example to show people how to implement remoting
+Channels for mono. I tried to keep it as simple as possible, so it is not
+feature complete.
+
+Overview
+========
+
+SimpleMessageFormat.cs: Contains routines to read/write messages transfered on
+the network (low level message format)
+
+SimpleWireFormat.cs: This is the data formatter.
+
+SimpleClientChannel.cs: The client side of the channel.
+
+ SimpleClientFormatterSink.cs: client side formatter sink
+ SimpleClientFormatterSinkProvider.cs: and the formatter sink provider
+
+ SimpleClientTransportSink.cs: client side transport sink
+ SimpleClientTransportSinkProvider.cs: and the transport sink provider
+
+SimpleServerChannel.cs: The server side of the channel.
+
+ SimpleServerFormatterSink.cs: server side formatter sink
+ SimpleServerFormatterSinkProvider.cs: and the formatter sink provider
+
+ SimpleServerTransportSink.cs: server side transport sink.
+
+SimpleChannel.cs: combines SimpleClientChannel with SimpleServerChannel.
+
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleChannel.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.Runtime.Remoting.Messaging;
+using System.Text.RegularExpressions;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleChannel : IChannelReceiver, IChannel,
+ IChannelSender
+ {
+ private int tcp_port;
+
+ public SimpleChannel ()
+ {
+ tcp_port = 0;
+ }
+
+ public SimpleChannel (int port)
+ {
+ tcp_port = port;
+ }
+
+ [MonoTODO]
+ public SimpleChannel (IDictionary properties,
+ IClientChannelSinkProvider clientSinkProvider,
+ IServerChannelSinkProvider serverSinkProvider)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public object ChannelData
+ {
+ [MonoTODO]
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public string ChannelName
+ {
+ [MonoTODO]
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public int ChannelPriority
+ {
+ [MonoTODO]
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ [MonoTODO]
+ public IMessageSink CreateMessageSink (string url,
+ object remoteChannelData,
+ out string objectURI)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public string[] GetUrlsForUri (string objectURI)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public string Parse (string url, out string objectURI)
+ {
+ int port;
+
+ string host = ParseSimpleURL (url, out objectURI, out port);
+
+ return "tcp://" + host + ":" + port;
+ }
+
+ [MonoTODO]
+ public void StartListening (object data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public void StopListening (object data)
+ {
+ throw new NotImplementedException ();
+ }
+
+ internal static string ParseSimpleURL (string url, out string objectURI, out int port)
+ {
+ // format: "simple://host:port/path/to/object"
+
+ objectURI = null;
+ port = 0;
+
+ Match m = Regex.Match (url, "simple://([^:]+):([0-9]+)(/.*)");
+
+ if (!m.Success)
+ return null;
+
+ string host = m.Groups[1].Value;
+ string port_str = m.Groups[2].Value;
+ objectURI = m.Groups[3].Value;
+ port = Convert.ToInt32 (port_str);
+
+ return host;
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleClientChannel.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleClientChannel : IChannelSender, IChannel
+ {
+ int priority = 1;
+ string name = "tcp";
+ IClientChannelSinkProvider sink_provider;
+
+ public SimpleClientChannel ()
+ {
+ sink_provider = new SimpleClientFormatterSinkProvider ();
+ sink_provider.Next = new SimpleClientTransportSinkProvider ();
+ }
+
+ public SimpleClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
+ {
+ priority = 1;
+ sink_provider = sinkProvider;
+
+ // add the tcp provider at the end of the chain
+ IClientChannelSinkProvider prov = sinkProvider;
+ while (prov.Next != null) prov = prov.Next;
+ prov.Next = new SimpleClientTransportSinkProvider ();
+ }
+
+ public SimpleClientChannel (string name, IClientChannelSinkProvider sinkProvider)
+ {
+ priority = 1;
+ this.name = name;
+ sink_provider = sinkProvider;
+
+ // add the tcp provider at the end of the chain
+ IClientChannelSinkProvider prov = sinkProvider;
+ while (prov.Next != null) prov = prov.Next;
+ prov.Next = new SimpleClientTransportSinkProvider ();
+ }
+
+ public string ChannelName
+ {
+ get {
+ return name;
+ }
+ }
+
+ public int ChannelPriority
+ {
+ get {
+ return priority;
+ }
+ }
+
+ public IMessageSink CreateMessageSink (string url,
+ object remoteChannelData,
+ out string objectURI)
+ {
+ if (url == null && remoteChannelData != null) {
+ IChannelDataStore ds = remoteChannelData as IChannelDataStore;
+ if (ds != null)
+ url = ds.ChannelUris [0];
+ }
+
+ if (Parse (url, out objectURI) == null)
+ return null;
+
+ return (IMessageSink) sink_provider.CreateSink (this, url, remoteChannelData);
+ }
+
+ public string Parse (string url, out string objectURI)
+ {
+ int port;
+
+ string host = SimpleChannel.ParseSimpleURL (url, out objectURI, out port);
+
+ return "tcp://" + host + ":" + port;
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleClientFormatterSink.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.IO;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleClientFormatterSink : IClientFormatterSink,
+ IMessageSink, IClientChannelSink, IChannelSinkBase
+ {
+ IClientChannelSink nextInChain;
+ SimpleWireFormat format = new SimpleWireFormat ();
+
+ public SimpleClientFormatterSink (IClientChannelSink nextSink)
+ {
+ nextInChain = nextSink;
+ }
+
+ public IClientChannelSink NextChannelSink
+ {
+ get {
+ return nextInChain;
+ }
+ }
+
+ public IMessageSink NextSink
+ {
+ get {
+ return (IMessageSink) nextInChain;
+ }
+ }
+
+ public IDictionary Properties
+ {
+ get {
+ return null;
+ }
+ }
+
+ public IMessageCtrl AsyncProcessMessage (IMessage msg,
+ IMessageSink replySink)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void AsyncProcessRequest (IClientChannelSinkStack sinkStack,
+ IMessage msg,
+ ITransportHeaders headers,
+ Stream stream)
+ {
+ // never called because the formatter sink is
+ // always the first in the chain
+ throw new NotSupportedException ();
+ }
+
+ [MonoTODO]
+ public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
+ object state,
+ ITransportHeaders headers,
+ Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Stream GetRequestStream (IMessage msg,
+ ITransportHeaders headers)
+ {
+ // never called
+ throw new NotSupportedException ();
+ }
+
+ public void ProcessMessage (IMessage msg,
+ ITransportHeaders requestHeaders,
+ Stream requestStream,
+ out ITransportHeaders responseHeaders,
+ out Stream responseStream)
+ {
+ // never called because the formatter sink is
+ // always the first in the chain
+ throw new NotSupportedException ();
+ }
+
+ public IMessage SyncProcessMessage (IMessage msg)
+ {
+ IMethodCallMessage call = (IMethodCallMessage)msg;
+
+ // we catch all exceptions to return them as message
+ try {
+ // create a new header
+ TransportHeaders req_headers = new TransportHeaders ();
+
+ //fixme: set some header values
+
+ Stream out_stream = new MemoryStream ();
+
+ // serialize msg to the stream
+ format.SerializeRequest (out_stream, msg);
+
+ // call the next sink
+ ITransportHeaders resp_headers;
+ Stream resp_stream;
+ nextInChain.ProcessMessage (msg, req_headers, out_stream, out resp_headers,
+ out resp_stream);
+
+ // deserialize resp_stream
+ IMessage result = (IMessage) format.DeserializeResponse (resp_stream, call);
+
+ // it's save to close the stream now
+ resp_stream.Close ();
+
+ return result;
+
+ } catch (Exception e) {
+ return new ReturnMessage (e, call);
+ }
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleClientFormatterSinkProvider.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleClientFormatterSinkProvider :
+ IClientFormatterSinkProvider, IClientChannelSinkProvider
+ {
+ IClientChannelSinkProvider next = null;
+
+ // add any sink properties here (private fields)
+
+ public SimpleClientFormatterSinkProvider ()
+ {
+ // nothing to do
+ }
+
+ public SimpleClientFormatterSinkProvider (IDictionary properties,
+ ICollection providerData)
+ {
+ // copy the contained properties to private fields
+
+ // add a check that there is no providerData
+ }
+
+ public IClientChannelSinkProvider Next
+ {
+ get {
+ return next;
+ }
+
+ set {
+ next = value;
+ }
+ }
+
+ public IClientChannelSink CreateSink (IChannelSender channel,
+ string url,
+ object remoteChannelData)
+ {
+ IClientChannelSink next_sink = null;
+ SimpleClientFormatterSink result;
+
+ if (next != null)
+ next_sink = next.CreateSink (channel, url, remoteChannelData);
+
+ result = new SimpleClientFormatterSink (next_sink);
+
+ // set properties on the newly creates sink
+
+ return result;
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleClientTransportSink.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+
+ internal class SimpleClientTransportSink : IClientChannelSink
+ {
+ string host;
+ string object_uri;
+ int port;
+
+ TcpClient tcpclient;
+
+ public SimpleClientTransportSink (string url)
+ {
+ host = SimpleChannel.ParseSimpleURL (url, out object_uri, out port);
+ tcpclient = new TcpClient ();
+ }
+
+ 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 stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
+ object state, ITransportHeaders headers,
+ Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
+ {
+ // no direct access to the stream
+ return null;
+ }
+
+ public void ProcessMessage (IMessage msg,
+ ITransportHeaders requestHeaders,
+ Stream requestStream,
+ out ITransportHeaders responseHeaders,
+ out Stream responseStream)
+ {
+ // get a network stream
+ tcpclient.Connect (host, port);
+ Stream network_stream = tcpclient.GetStream ();
+
+ // send the message
+ SimpleMessageFormat.SendMessageStream (network_stream, (MemoryStream)requestStream,
+ SimpleMessageFormat.MessageType.Request,
+ object_uri);
+
+ Console.WriteLine ("Client ProcessMessage");
+
+ // read the response fro the network an copy it to a memory stream
+ SimpleMessageFormat.MessageType msg_type;
+ string uri;
+ MemoryStream mem_stream = SimpleMessageFormat.ReceiveMessageStream (network_stream, out msg_type, out uri);
+
+ // close the stream
+ tcpclient.Close ();
+
+ switch (msg_type) {
+ case SimpleMessageFormat.MessageType.Response:
+ //fixme: read response message
+ responseHeaders = null;
+
+ responseStream = mem_stream;
+
+ break;
+ default:
+ throw new Exception ("unknown response mesage header");
+ }
+ }
+
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleClientTransportSinkProvider.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.IO;
+using System.Net.Sockets;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleClientTransportSinkProvider : IClientChannelSinkProvider
+ {
+ public SimpleClientTransportSinkProvider ()
+ {
+ // 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 SimpleClientTransportSink (url);
+ }
+ }
+}
--- /dev/null
+// System.Runtime.Remoting.Channels.Simple.SimpleMessageFormat.cs
+//
+// Author:
+// DietmarMaurer (dietmar@ximian.com)
+//
+// (C) 2002 Ximian, Inc. http://www.ximian.com
+
+using System.Runtime.Serialization.Formatters;
+using System.Runtime.Serialization;
+using System.Reflection;
+using System.Collections;
+using System.IO;
+using System.Runtime.Remoting.Messaging;
+
+namespace System.Runtime.Remoting.Channels.Simple {
+
+ public sealed class SimpleMessageFormat
+ {
+ public enum MessageType : byte {
+ Request = 0,
+ Response = 1,
+ Exception = 2,
+ Unknown = 3
+ }
+
+ public SimpleMessageFormat ()
+ {
+ }
+
+ public static void SendExceptionMessage (Stream network_stream, string message)
+ {
+ // we use the uri field to encode the message text
+ SendMessageStream (network_stream, null, MessageType.Exception, message);
+ }
+
+ public static void SendMessageStream (Stream network_stream, MemoryStream data,
+ MessageType msg_type, string uri)
+ {
+ int data_len = 0;
+
+ if (data != null)
+ data_len = (int)data.Length;
+
+ int uri_len = 0;
+
+ if (uri != null)
+ uri_len = uri.Length;
+
+ int header_len = 12 + uri_len * 2;
+ int msg_len = data_len + header_len;
+
+ byte [] buffer = new byte [msg_len];
+
+ // magic header signature
+ buffer [0] = 255;
+ buffer [1] = 0;
+ buffer [2] = 255;
+ buffer [3] = (byte) msg_type;
+
+ // data length
+ buffer [4] = (byte) data_len;
+ buffer [5] = (byte) (data_len >> 8);
+ buffer [6] = (byte) (data_len >> 16);
+ buffer [7] = (byte) (data_len >> 24);
+
+ // uri length
+ buffer [8] = (byte) uri_len;
+ buffer [9] = (byte) (uri_len >> 8);
+ buffer [10] = (byte) (uri_len >> 16);
+ buffer [11] = (byte) (uri_len >> 24);
+
+ // uri
+ for (int i = 0; i < uri_len; i++) {
+ buffer [12 + i*2] = (byte) uri [i];
+ buffer [13 + i*2] = (byte) (uri [i] >> 8);
+ }
+
+ if (data_len > 0) {
+ byte [] data_buffer = data.GetBuffer ();
+ for (int i = 0; i < data_len; i++)
+ buffer [i + header_len] = data_buffer [i];
+ }
+
+ network_stream.Write (buffer, 0, msg_len);
+ }
+
+ public static MemoryStream ReceiveMessageStream (Stream network_stream,
+ out MessageType msg_type,
+ out string uri)
+ {
+ int data_len = 0;
+ int uri_len = 0;
+ msg_type = MessageType.Unknown;
+ uri = null;
+
+ // search for message header (255, 0, 255, msg_type, msg_len)
+ while (true) {
+ while (true) {
+ int x = network_stream.ReadByte ();
+ if (x != 255)
+ continue;
+ x = network_stream.ReadByte ();
+ if (x != 0)
+ continue;
+ x = network_stream.ReadByte ();
+ if (x != 255)
+ continue;
+ break;
+ }
+
+ msg_type = (MessageType)network_stream.ReadByte ();
+
+ byte [] buffer = new byte [8];
+
+ int bytes_read = network_stream.Read (buffer, 0, 8);
+ if (bytes_read != 8)
+ continue;
+
+ data_len = (buffer [0] | (buffer [1] << 8) |
+ (buffer [2] << 16) | (buffer [3] << 24));
+
+ uri_len = (buffer [4] | (buffer [5] << 8) |
+ (buffer [6] << 16) | (buffer [7] << 24));
+
+ if (uri_len > 0) {
+ byte [] uri_buffer = new byte [uri_len * 2];
+ bytes_read = network_stream.Read (uri_buffer, 0, uri_len * 2);
+ if (bytes_read != (uri_len * 2))
+ continue;
+ char [] uri_array = new char [uri_len];
+ for (int i = 0; i < uri_len; i++) {
+ uri_array [i] = (char) (uri_buffer [i * 2] | (uri_buffer [(i * 2) + 1] << 8));
+ }
+ uri = new string (uri_array);
+ }
+ break;
+ }
+
+ if (msg_type == MessageType.Exception)
+ throw new RemotingException ("\n" + uri + "\n" + "Rethrown at:\n");
+
+ byte [] stream_buffer = new byte [data_len];
+ if ((network_stream.Read (stream_buffer, 0, data_len)) != data_len)
+ throw new Exception ("packet size error");
+
+ return new MemoryStream (stream_buffer, false);
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleServerChannel.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+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;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleServerChannel : IChannelReceiver, IChannel
+ {
+ int port = 0;
+ string name = "tcp";
+ string host;
+ int priority = 1;
+ Thread server_thread = null;
+ TcpListener listener;
+ SimpleServerTransportSink sink;
+ ChannelDataStore channel_data;
+
+ void Init (IServerChannelSinkProvider provider) {
+ if (provider == null) {
+ provider = new SimpleServerFormatterSinkProvider ();
+ }
+
+ IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (provider, this);
+
+ host = Dns.GetHostByName(Dns.GetHostName()).HostName;
+
+ string [] uris = null;
+
+ if (port != 0) {
+ uris = new String [1];
+ uris [0] = GetChannelUri ();
+ }
+
+ channel_data = new ChannelDataStore (uris);;
+
+ sink = new SimpleServerTransportSink (next_sink);
+
+ listener = new TcpListener (port);
+ StartListening (null);
+ }
+
+ public SimpleServerChannel (int port)
+ {
+ this.port = port;
+ Init (null);
+ }
+
+ public SimpleServerChannel (IDictionary properties,
+ IServerChannelSinkProvider serverSinkProvider)
+ {
+ port = (int)properties ["port"];
+ Init (serverSinkProvider);
+ }
+
+ public SimpleServerChannel (string name, int port,
+ IServerChannelSinkProvider serverSinkProvider)
+ {
+ name = name;
+ this.port = port;
+ Init (serverSinkProvider);
+ }
+
+ public SimpleServerChannel (string name, int port)
+ {
+ name = name;
+ this.port = port;
+ Init (null);
+ }
+
+ public object ChannelData
+ {
+ get {
+ return channel_data;
+ }
+ }
+
+ public string ChannelName
+ {
+ get {
+ return name;
+ }
+ }
+
+ public int ChannelPriority
+ {
+ get {
+ return priority;
+ }
+ }
+
+ public string GetChannelUri ()
+ {
+ return "tcp://" + host + ":" + port;
+ }
+
+ public string[] GetUrlsForUri (string uri)
+ {
+ string [] result = new String [1];
+
+ if (uri.IndexOf ('/') != 0)
+ result [0] = GetChannelUri () + "/" + uri;
+ else
+ result [0] = GetChannelUri () + uri;
+
+ return result;
+ }
+
+ public string Parse (string url, out string objectURI)
+ {
+ int port;
+
+ string host = SimpleChannel.ParseSimpleURL (url, out objectURI, out port);
+
+ return "tcp://" + host + ":" + port;
+ }
+
+ void WaitForConnections ()
+ {
+ while (true) {
+ TcpClient client = listener.AcceptTcpClient ();
+
+ sink.InternalProcessMessage (client.GetStream ());
+
+ client.Close ();
+ }
+ }
+
+ public void StartListening (object data)
+ {
+ if (server_thread == null) {
+ listener.Start ();
+ if (port == 0) {
+ port = ((IPEndPoint)listener.LocalEndpoint).Port;
+ channel_data.ChannelUris = new String [1];
+ channel_data.ChannelUris [0] = GetChannelUri ();
+ }
+
+ server_thread = new Thread (new ThreadStart (WaitForConnections));
+ server_thread.Start ();
+ }
+ }
+
+ public void StopListening (object data)
+ {
+ if (server_thread != null) {
+ server_thread.Abort ();
+ server_thread = null;
+ listener.Stop ();
+ }
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleServerFormatterSink.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.IO;
+using System.Runtime.Remoting.Messaging;
+
+namespace System.Runtime.Remoting.Channels.Simple {
+
+ public class SimpleServerFormatterSink : IServerChannelSink, IChannelSinkBase
+ {
+ IServerChannelSink next_sink;
+ SimpleWireFormat format = new SimpleWireFormat ();
+
+ public SimpleServerFormatterSink (IServerChannelSink nextSink)
+ {
+ next_sink = nextSink;
+ }
+
+ public IServerChannelSink NextChannelSink {
+ get {
+ return next_sink;
+ }
+ }
+
+ public IDictionary Properties {
+ get {
+ return null;
+ }
+ }
+
+ [MonoTODO]
+ public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
+ IMessage msg, ITransportHeaders headers, Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
+ IMessage msg, ITransportHeaders headers)
+ {
+ // never called
+ throw new NotSupportedException ();
+ }
+
+ public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
+ IMessage requestMsg,
+ ITransportHeaders requestHeaders,
+ Stream requestStream,
+ out IMessage responseMsg,
+ out ITransportHeaders responseHeaders,
+ out Stream responseStream)
+ {
+ IMessage call;
+
+ string uri = (string)requestHeaders ["_requestUri"];
+
+ if (requestMsg == null) {
+ call = (IMessage)format.DeserializeRequest (requestStream, uri);
+ } else {
+ call = requestMsg;
+ }
+
+ next_sink.ProcessMessage (sinkStack, call, requestHeaders, null,
+ out responseMsg, out responseHeaders, out responseStream);
+
+ responseStream = new MemoryStream ();
+
+ format.SerializeResponse (responseStream, responseMsg);
+
+ responseStream.Position = 0;
+
+ return ServerProcessing.Complete;
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleServerFormatterSinkProvider.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ public class SimpleServerFormatterSinkProvider :
+ IServerFormatterSinkProvider, IServerChannelSinkProvider
+ {
+ IServerChannelSinkProvider next = null;
+
+ public SimpleServerFormatterSinkProvider ()
+ {
+ }
+
+ [MonoTODO]
+ public SimpleServerFormatterSinkProvider (IDictionary properties,
+ ICollection providerData)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public IServerChannelSinkProvider Next
+ {
+ get {
+ return next;
+ }
+
+ set {
+ next = value;
+ }
+ }
+
+ public IServerChannelSink CreateSink (IChannelReceiver channel)
+ {
+ IServerChannelSink next_sink = null;
+ SimpleServerFormatterSink result;
+
+ if (next != null)
+ next_sink = next.CreateSink (channel);
+
+ result = new SimpleServerFormatterSink (next_sink);
+
+ // set properties on result
+
+ return result;
+ }
+
+ public void GetChannelData (IChannelDataStore channelData)
+ {
+ // no idea why we need this
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.Simple.SimpleServerTransportSink.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+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;
+
+namespace System.Runtime.Remoting.Channels.Simple
+{
+ internal class SimpleServerTransportSink : IServerChannelSink, IChannelSinkBase
+ {
+ IServerChannelSink next_sink;
+
+ public SimpleServerTransportSink (IServerChannelSink next)
+ {
+ next_sink = next;
+ }
+
+ public IServerChannelSink NextChannelSink {
+ get {
+ return next_sink;
+ }
+ }
+
+ [MonoTODO]
+ public IDictionary Properties {
+ get {
+ throw new NotImplementedException ();
+ }
+ }
+
+ [MonoTODO]
+ public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
+ IMessage msg, ITransportHeaders headers, Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
+ IMessage msg, ITransportHeaders headers)
+ {
+ throw new NotImplementedException ();
+ }
+
+ 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 SimpleServerChannel does not call it.
+ throw new NotSupportedException ();
+ }
+
+ internal void InternalProcessMessage (Stream network_stream)
+ {
+ try {
+ string uri;
+ SimpleMessageFormat.MessageType msg_type;
+ MemoryStream msg_stream;
+
+ msg_stream = SimpleMessageFormat.ReceiveMessageStream (network_stream,
+ out msg_type, out uri);
+ if (msg_type != SimpleMessageFormat.MessageType.Request)
+ throw new RemotingException ("received wrong message type");
+
+ TransportHeaders headers = new TransportHeaders ();
+ headers ["_requestUri"] = uri;
+
+ Console.WriteLine ("ProcessMessageInternal " + uri);
+
+ IMessage resp_message;
+ ITransportHeaders resp_headers;
+ Stream resp_stream;
+ ServerProcessing res = next_sink.ProcessMessage (null, null, headers, msg_stream,
+ out resp_message, out resp_headers,
+ out resp_stream);
+
+ switch (res) {
+ case ServerProcessing.Complete:
+ // send the response
+ SimpleMessageFormat.SendMessageStream (network_stream,
+ (MemoryStream)resp_stream,
+ SimpleMessageFormat.MessageType.Response,
+ null);
+
+ break;
+ case ServerProcessing.Async:
+ case ServerProcessing.OneWay:
+ throw new NotImplementedException ();
+ }
+
+ } catch (Exception e) {
+ SimpleMessageFormat.SendExceptionMessage (network_stream, e.ToString ());
+ }
+ }
+ }
+}
--- /dev/null
+// System.Runtime.Remoting.Channels.Simple.SimpleWireFormat.cs
+//
+// Author:
+// DietmarMaurer (dietmar@ximian.com)
+//
+// (C) 2002 Ximian, Inc. http://www.ximian.com
+
+using System.Runtime.Serialization.Formatters;
+using System.Runtime.Serialization;
+using System.Reflection;
+using System.Collections;
+using System.IO;
+using System.Runtime.Remoting.Messaging;
+
+namespace System.Runtime.Remoting.Channels.Simple {
+
+ public sealed class SimpleWireFormat
+ {
+ enum TypeId : byte {
+ Boolean,
+ Byte,
+ Char,
+ Decimal,
+ Double,
+ Int16,
+ Int32,
+ Int64,
+ SByte,
+ String,
+ Single,
+ UInt16,
+ UInt32,
+ UInt64,
+ Exception,
+ NULL
+ }
+
+ public SimpleWireFormat ()
+ {
+ }
+
+
+ void SerializeObject (BinaryWriter writer, object obj)
+ {
+ Type type = obj.GetType ();
+
+ if (obj == null) {
+ writer.Write ((byte)TypeId.NULL);
+ return;
+ }
+
+ if (type == typeof (String)) {
+ writer.Write ((byte)TypeId.String);
+ writer.Write ((String)obj);
+ return;
+ }
+
+ if (type == typeof (int)) {
+ writer.Write ((byte)TypeId.Int32);
+ writer.Write ((int)obj);
+ return;
+ }
+
+ if (type == typeof (bool)) {
+ writer.Write ((byte)TypeId.Boolean);
+ writer.Write ((bool)obj);
+ return;
+ }
+
+ Exception e = obj as Exception;
+ if (e != null) {
+ writer.Write ((byte)TypeId.Exception);
+ writer.Write (e.Message);
+ return;
+ }
+
+ throw new NotSupportedException ();
+ }
+
+ object DeserializeObject (BinaryReader reader)
+ {
+ TypeId tid = (TypeId)reader.ReadByte ();
+
+ if (tid == TypeId.NULL)
+ return null;
+
+ if (tid == TypeId.String) {
+ return reader.ReadString ();
+ }
+
+ if (tid == TypeId.Int32) {
+ return reader.ReadInt32 ();
+ }
+
+ if (tid == TypeId.Boolean) {
+ return reader.ReadBoolean ();
+ }
+
+ if (tid == TypeId.Exception) {
+ return new RemotingException (reader.ReadString ());
+ }
+
+ throw new NotSupportedException ();
+ }
+
+ public IMethodCallMessage DeserializeRequest (Stream serializationStream, string uri)
+ {
+ if (serializationStream == null) {
+ throw new ArgumentNullException ("serializationStream is null");
+ }
+
+ Type svr_type = RemotingServices.GetServerTypeForUri (uri);
+ if (svr_type == null)
+ throw new RemotingException ("no registered server for uri " + uri);
+
+ BinaryReader reader = new BinaryReader (serializationStream);
+
+ string method_name = reader.ReadString ();
+ int arg_count = reader.ReadInt32 ();
+
+ object [] args = new object [arg_count];
+ for (int i = 0; i < arg_count; i++) {
+ args [i] = DeserializeObject (reader);
+ }
+
+ MonoMethodMessage msg = new MonoMethodMessage (svr_type, method_name, args);
+
+ Console.WriteLine ("Deserialize " + msg);
+
+ return msg;
+ }
+
+ public IMethodReturnMessage DeserializeResponse (Stream serializationStream,
+ IMethodCallMessage request)
+ {
+
+ BinaryReader reader = new BinaryReader (serializationStream);
+
+
+ object return_value = DeserializeObject (reader);
+ Exception e = return_value as Exception;
+ if (e != null)
+ return new ReturnMessage (e, request);
+
+ int arg_count = reader.ReadInt32 ();
+ object [] out_args = new object [arg_count];
+ for (int i = 0; i < arg_count; i++)
+ out_args [i] = DeserializeObject (reader);
+
+ return new ReturnMessage (return_value, out_args, arg_count, null, request);
+ }
+
+ public void SerializeRequest (Stream serializationStream, object graph)
+ {
+ if (serializationStream == null) {
+ throw new ArgumentNullException ("serializationStream is null");
+ }
+
+ BinaryWriter writer = new BinaryWriter (serializationStream);
+
+ IMethodCallMessage msg = graph as IMethodCallMessage;
+ if (msg != null) {
+ writer.Write (msg.MethodName);
+ writer.Write ((int)msg.InArgCount);
+ for (int i = 0; i < msg.InArgCount; i++)
+ SerializeObject (writer, msg.GetInArg (i));
+ return;
+ }
+
+ throw new NotSupportedException ();
+ }
+
+ public void SerializeResponse (Stream serializationStream, object graph)
+ {
+ if (serializationStream == null) {
+ throw new ArgumentNullException ("serializationStream is null");
+ }
+
+ BinaryWriter writer = new BinaryWriter (serializationStream);
+
+ IMethodReturnMessage res = graph as IMethodReturnMessage;
+ if (res != null) {
+
+ if (res.Exception != null) {
+ SerializeObject (writer, res.Exception);
+ return;
+ }
+
+ SerializeObject (writer, res.ReturnValue);
+ writer.Write (res.OutArgCount);
+
+ for (int i = 0; i < res.OutArgCount; i++)
+ SerializeObject (writer, res.GetOutArg (i));
+
+ return;
+ }
+
+ throw new NotSupportedException ();
+ }
+ }
+}
//
-// System.Runtime.Remoting.Channels.Tcp.TcpChannel.cs
+// System.Runtime.Remoting.Channels.Tcp.TcpServerChannel.cs
//
// Author: Rodrigo Moya (rodrigo@ximian.com)
//
<csc target="library" output="../lib/System.Runtime.Remoting.dll" debug="${debug}">
<arg value="/nowarn:1595"/>
<arg value="/unsafe"/>
+ <arg value="/noconfig"/> <!-- don't reference ms assemblies -->
+ <arg value="/lib:../lib/"/>
+ <arg value="/r:corlib.dll"/>
+ <arg value="/r:System.dll"/>
<sources>
<includes name="**/*.cs"/>
<excludes name="Test/**"/>
</sources>
- <references>
- <includes name="../lib/corlib.dll"/>
- <includes name="../lib/System.dll"/>
- </references>
</csc>
</target>
<target name="clean">
throw new NotImplementedException ();
}
- [MonoTODO]
public static IServerChannelSink CreateServerChannelSinkChain (
IServerChannelSinkProvider provider,
IChannelReceiver channel)
{
- throw new NotImplementedException ();
+ IServerChannelSinkProvider tmp = provider;
+ while (tmp.Next != null) tmp = tmp.Next;
+ tmp.Next = new ServerDispatchSinkProvider ();
+
+ return provider.CreateSink (channel);
}
[MonoTODO]
--- /dev/null
+//
+// System.Runtime.Remoting.Channels/ServerDispatchSink.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+using System.IO;
+using System.Runtime.Remoting.Messaging;
+
+namespace System.Runtime.Remoting.Channels {
+
+ internal class ServerDispatchSink : IServerChannelSink, IChannelSinkBase
+ {
+ public ServerDispatchSink ()
+ {
+ }
+
+ public IServerChannelSink NextChannelSink {
+ get {
+ return null;
+ }
+ }
+
+ public IDictionary Properties {
+ get {
+ return null;
+ }
+ }
+
+ [MonoTODO]
+ public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
+ IMessage msg, ITransportHeaders headers, Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
+ IMessage msg, ITransportHeaders headers)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
+ IMessage requestMsg,
+ ITransportHeaders requestHeaders,
+ Stream requestStream,
+ out IMessage responseMsg,
+ out ITransportHeaders responseHeaders,
+ out Stream responseStream)
+ {
+ IMethodCallMessage call = (IMethodCallMessage)requestMsg;
+
+ string uri = (string)requestHeaders ["_requestUri"];
+
+ MarshalByRefObject svr = RemotingServices.GetServerForUri (uri);
+ if (svr == null)
+ throw new RemotingException ("no registered server for uri " + uri);
+
+ responseMsg = RemotingServices.ExecuteMessage (svr, call);
+ responseHeaders = null;
+ responseStream = null;
+
+ return ServerProcessing.Complete;
+ }
+ }
+}
--- /dev/null
+//
+// System.Runtime.Remoting.Channels.ServerDispatchSinkProvider.cs
+//
+// Author: Dietmar Maurer (dietmar@ximian.com)
+//
+// 2002 (C) Copyright, Ximian, Inc.
+//
+
+using System.Collections;
+
+namespace System.Runtime.Remoting.Channels
+{
+ internal class ServerDispatchSinkProvider :
+ IServerFormatterSinkProvider, IServerChannelSinkProvider
+ {
+ public ServerDispatchSinkProvider ()
+ {
+ }
+
+ [MonoTODO]
+ public ServerDispatchSinkProvider (IDictionary properties,
+ ICollection providerData)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public IServerChannelSinkProvider Next
+ {
+ get {
+ return null;
+ }
+
+ set {
+ throw new NotSupportedException ();
+ }
+ }
+
+ public IServerChannelSink CreateSink (IChannelReceiver channel)
+ {
+ return new ServerDispatchSink ();
+ }
+
+ public void GetChannelData (IChannelDataStore channelData)
+ {
+ // no idea why we need this
+ }
+ }
+}
// System.Runtime.Remoting.Channels.TransportHeaders.cs
//
// Author: Rodrigo Moya (rodrigo@ximian.com)
+// Dietmar Maurer (dietmar@ximian.com)
//
// 2002 (C) Copyright, Ximian, Inc.
//
{
public class TransportHeaders : ITransportHeaders
{
- [MonoTODO]
+ Hashtable hash_table;
+
public TransportHeaders ()
{
- throw new NotImplementedException ();
+ hash_table = new Hashtable ();
}
- public object this[object key]
+ public object this [object key]
{
- [MonoTODO]
get {
- throw new NotImplementedException ();
+ return hash_table [key];
}
- [MonoTODO]
set {
- throw new NotImplementedException ();
+ hash_table [key] = value;
}
}
- [MonoTODO]
public IEnumerator GetEnumerator ()
{
- throw new NotImplementedException ();
+ return hash_table.GetEnumerator ();
}
}
}
namespace System.Runtime.Remoting.Messaging {
- internal class MonoMethodMessage : IMethodCallMessage, IMethodReturnMessage {
+ public class MonoMethodMessage : IMethodCallMessage, IMethodReturnMessage {
MonoMethod method;
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal extern void InitMessage (MonoMethod method, object [] out_args);
- public MonoMethodMessage (MonoMethod method, object [] out_args)
+ public MonoMethodMessage (MethodBase method, object [] out_args)
{
- InitMessage (method, out_args);
+ InitMessage ((MonoMethod)method, out_args);
+ }
+
+ public MonoMethodMessage (Type type, string method_name, object [] in_args)
+ {
+ // fixme: consider arg types
+ MethodInfo minfo = type.GetMethod (method_name);
+
+ InitMessage ((MonoMethod)minfo, null);
+
+ int len = in_args.Length;
+ for (int i = 0; i < len; i++) {
+ args [i] = in_args [i];
+ }
}
public IDictionary Properties {
//
// Author:
// Miguel de Icaza (miguel@ximian.com)
+// Dietmar Maurer (dietmar@ximian.com)
//
// (C) Ximian, Inc. http://www.ximian.com
//
public class ObjRef : IObjectReference, ISerializable {
MarshalByRefObject mbr;
SerializationInfo si;
+ string uri;
Type type;
public ObjRef ()
// This encarnates the object from serialized data.
}
+ [MonoTODO]
+ public virtual IChannelInfo ChannelInfo {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ [MonoTODO]
+ public virtual IEnvoyInfo EnvoyInfo {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ [MonoTODO]
+ public virtual IRemotingTypeInfo TypeInfo {
+ get {
+ throw new NotImplementedException ();
+ }
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ public virtual string URI {
+ get {
+ return uri;
+ }
+ set {
+ uri = value;
+ }
+ }
+
[MonoTODO]
public virtual void GetObjectData (SerializationInfo si, StreamingContext sc)
{
using System;
using System.Reflection;
+using System.Threading;
+using System.Collections;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Channels;
return real_proxy.GetTransparentProxy ();
}
+
+ public static Type GetServerTypeForUri (string uri)
+ {
+ object svr = GetServerForUri (uri);
+
+ if (svr == null)
+ return null;
+
+ return svr.GetType ();
+ }
+
+ static Hashtable uri_hash = new Hashtable ();
+
+ private static void RegisterServerForUri (MarshalByRefObject obj, string uri)
+ {
+ uri_hash [uri] = obj;
+ }
+
+ public static object Unmarshal (ObjRef objref)
+ {
+ throw new NotImplementedException ();
+ }
+
+ internal static MarshalByRefObject GetServerForUri (string uri)
+ {
+ return (MarshalByRefObject)uri_hash [uri];
+ }
+
+ static Mutex mtx = new Mutex ();
+
+ public static ObjRef Marshal (MarshalByRefObject obj, string uri)
+ {
+ return Marshal (obj, uri, null);
+ }
+
+ public static ObjRef Marshal (MarshalByRefObject obj, string uri, Type requested_type)
+ {
+ if (RemotingServices.IsTransparentProxy (obj))
+ throw new RemotingException ("its not possible marshal proxy objects");
+
+ // fixme: handle requested_type
+
+ Type type = obj.GetType ();
+
+ ObjRef res = null;
+
+ try {
+ mtx.WaitOne ();
+
+ object svr = GetServerForUri (uri);
+
+ if (svr != null) {
+ if (obj != svr)
+ throw new RemotingException ("uri already in use, " + uri);
+
+ // already registered
+ } else {
+ RegisterServerForUri (obj, uri);
+ }
+
+ res = obj.CreateObjRef (requested_type);
+ res.URI = uri;
+
+ } finally {
+ mtx.ReleaseMutex ();
+ }
+
+ return res;
+ }
}
+
}
public virtual ObjRef CreateObjRef (Type type)
{
- return null;
+ return new ObjRef (this, type);
}
public object GetLifetimeService ()