[Mono-bugs] [Bug 54946][Cri] New - Remotinf with ChannelSink Interop with Microsoft

bugzilla-daemon@bugzilla.ximian.com bugzilla-daemon@bugzilla.ximian.com
Fri, 27 Feb 2004 13:24:55 -0500 (EST)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by jluciani@novell.com.

http://bugzilla.ximian.com/show_bug.cgi?id=54946

--- shadow/54946	2004-02-27 13:24:55.000000000 -0500
+++ shadow/54946.tmp.10383	2004-02-27 13:24:55.000000000 -0500
@@ -0,0 +1,1171 @@
+Bug#: 54946
+Product: Mono/Runtime
+Version: unspecified
+OS: 
+OS Details: 
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Critical
+Component: misc
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: jluciani@novell.com               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: Remotinf with ChannelSink Interop with Microsoft
+
+Please fill in this template when reporting a bug, unless you know what you
+are doing.
+Description of Problem:
+
+I have Client and Server ChannelSink components that exchange messages that
+contain empty streams, these channel sinks are configured into the channel
+sink chain by the Client and Server applications. When I execute the client
+ under Mono and the server under .NET, I get the following exception:
+
+Unhandled Exception: System.NotSupportedException: Unknown header code: 2
+ 
+Server stack trace:
+in <0x00132>
+System.Runtime.Remoting.Channels.Tcp.TcpMessageIO:ReceiveHeaders
+(System.IO.Stream,byte[])
+in <0x00196>
+System.Runtime.Remoting.Channels.Tcp.TcpMessageIO:ReceiveMessageStream
+(System.IO.Stream,System.Runtime.Remoting.Channels.ITransportHeaders&,byte[])
+in <0x0011e>
+System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink:ProcessMessage
+(System.Runtime.Remoting.Messaging.IMessage,System.Runtime.Remoting.Channels.ITransportHeaders,System.IO.Stream,System.Runtime.Remoting.Channels.ITransportHeaders&,System.IO.Stream&)
+in <0x000c8> ChannelSinkTest.ClientSink:ProcessMessage
+(System.Runtime.Remoting.Messaging.IMessage,System.Runtime.Remoting.Channels.ITransportHeaders,System.IO.Stream,System.Runtime.Remoting.Channels.ITransportHeaders&,System.IO.Stream&)
+in <0x0019b>
+System.Runtime.Remoting.Channels.BinaryClientFormatterSink:SyncProcessMessage
+(System.Runtime.Remoting.Messaging.IMessage)
+ 
+ 
+Exception rethrown at [0]:
+ 
+in (unmanaged) /usr/lib/libmono.so.0(mono_raise_exception+0x1c) [0x400ae34c]
+in (unmanaged) /usr/lib/libmono.so.0 [0x400c0f2c]
+in <0x00042> (wrapper remoting-invoke) ChannelSinkTest.LinePrinter:print
+(string)
+in <0x00032> (wrapper remoting-invoke-with-check)
+ChannelSinkTest.LinePrinter:print (string)
+in <0x000e7> ChannelSinkTest.Client:Main (string[])
+
+Comparing Lan traces of the server being accessed from a Windows client
+with the traces of the server being accessed from a Mono client show that
+the Mono client requests are missing the url when the request stream is
+empty, when this happens, the Windows server returns a message indicating
+that it has encountered an internal error.
+
+Steps to reproduce the problem:
+1. Build the following: ChannelSink, LinePrinter, Client, Server.
+
+The code for ChannelSink is:
+
+using System;
+
+using System.IO;
+
+using System.Collections;
+
+using System.Runtime.Remoting.Channels;
+
+using System.Runtime.Remoting;
+
+using System.Runtime.Remoting.Messaging;
+
+
+
+namespace ChannelSinkTest
+
+{
+
+   /// <summary>
+
+   /// ClientSink implementation.
+
+   /// </summary>
+
+   public class ClientSink: BaseChannelSinkWithProperties, IClientChannelSink
+
+   {
+
+      #region Class Members and Defines
+
+
+
+      private IClientChannelSink m_nextSink;
+
+
+
+      #endregion
+
+
+
+      /// <summary>
+
+      /// Constructor.
+
+      /// </summary>
+
+      /// <param name="next">The next sink in the chain</param>
+
+      public ClientSink(IClientChannelSink next)
+
+      {
+
+         Console.WriteLine("ClientSink instantiated");
+
+
+
+         m_nextSink = next;
+
+      }
+
+
+
+
+
+      /// <summary>
+
+      /// Processes message to be sent to the peer.
+
+      /// </summary>
+
+      /// <param name="requestMsg">Request message</param>
+
+      /// <param name="requestHeaders">Request transport headers</param>
+
+      /// <param name="requestStream">Request stream</param>
+
+      /// <param name="responseHeaders">Response transport headers</param>
+
+      /// <param name="responseStream">Response stream</param>
+
+      public void ProcessMessage(IMessage msg,
+
+         ITransportHeaders requestHeaders,
+
+         Stream requestStream,
+
+         out ITransportHeaders responseHeaders,
+
+         out Stream responseStream)
+
+      {
+
+         Console.WriteLine("ClientSink.ProcessMessage- Enter");
+
+
+
+         // Initialize output parameters
+
+         responseHeaders = null;
+
+         responseStream = null;
+
+
+
+         // Send primer message to the server
+
+         ITransportHeaders primerReqHeaders = new TransportHeaders();
+
+         primerReqHeaders["Content-Type"] = "text/xml; charset=\"utf-8\"";
+
+         primerReqHeaders["Primer"] = "PrimerMsg";
+
+         Stream primerReqStream = new MemoryStream();
+
+
+
+         // Forward the call to the next sink
+
+         m_nextSink.ProcessMessage(msg,
+
+            primerReqHeaders,
+
+            primerReqStream,
+
+            out responseHeaders,
+
+            out responseStream);
+
+
+
+         // Re-Initialize output parameters
+
+         responseHeaders = null;
+
+         responseStream = null;
+
+
+
+         // Set request header
+
+         requestHeaders["Primer"] = "NotPrimerMsg";
+
+         //requestHeaders["Content-Type"] = "text/xml; charset=\"utf-8\"";
+
+
+
+         // Forward the call to the next sink
+
+         m_nextSink.ProcessMessage(msg,
+
+            requestHeaders,
+
+            requestStream,
+
+            out responseHeaders,
+
+            out responseStream);
+
+
+
+         Console.WriteLine("ClientSink.ProcessMessage- Exit");
+
+      }
+
+
+
+      /// <summary>
+
+      /// Asynchronously process message to be sent to the peer.
+
+      /// </summary>
+
+      /// <param name="sinkStack">Client channel sink stack</param>
+
+      /// <param name="msg">Request message</param>
+
+      /// <param name="headers">Request transport headers</param>
+
+      /// <param name="stream">Request stream</param>
+
+      public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
+
+         IMessage msg,
+
+         ITransportHeaders headers,
+
+         Stream stream)
+
+      {
+
+         Console.WriteLine("ClientSink:AsyncProcessRequest- Enter");
+
+
+
+         // We do not have support for this yet
+
+         throw new Exception("SecureClientSink:AsyncProcessMessage: Async
+Remoting Not Supported Yet");
+
+
+
+         // Push onto stack and forward the request
+
+         //sinkStack.Push(this, asyncContext);
+
+         //m_nextSink.AsyncProcessRequest(sinkStack, msg, headers,
+streamProxy);
+
+      }
+
+
+
+      /// <summary>
+
+      /// Process response to message that was sent asynchronously to message.
+
+      /// </summary>
+
+      /// <param name="sinkStack">Client response channel sink stack</param>
+
+      /// <param name="contextObject">Context object</param>
+
+      /// <param name="headers">Response transport headers</param>
+
+      /// <param name="stream">Response stream</param>
+
+      public void AsyncProcessResponse(IClientResponseChannelSinkStack
+sinkStack,
+
+         object contextObject,
+
+         ITransportHeaders headers,
+
+         Stream stream)
+
+      {
+
+         Console.WriteLine("ClientSink:AsyncProcessResponse- Enter");
+
+
+
+         // We do not have support for this yet
+
+         throw new Exception("SecureClientSink:AsyncProcessResponse: Async
+Remoting Not Supported Yet");
+
+
+
+         // Forward the request
+
+         //sinkStack.AsyncProcessResponse(headers,stream);
+
+      }
+
+
+
+      /// <summary>
+
+      /// Requests a request stream from the next sink in the channel sink
+chain.
+
+      /// </summary>
+
+      /// <param name="msg">Message</param>
+
+      /// <param name="headers">Transport Headers</param>
+
+      /// <returns>Request stream</returns>
+
+      public Stream GetRequestStream(IMessage msg,
+
+         ITransportHeaders headers)
+
+      {
+
+         Console.WriteLine("ClientSink:GetRequestStream- Enter");
+
+
+
+         Stream stream = m_nextSink.GetRequestStream(msg, headers);
+
+
+
+         Console.WriteLine("ClientSink:GetRequestStream- Exit");
+
+
+
+         return stream;
+
+      }
+
+
+
+
+
+      /// <summary>
+
+      /// Returns the next sink in the channel chain.
+
+      /// </summary>
+
+      public IClientChannelSink NextChannelSink {get {return m_nextSink;}}
+
+   }
+
+
+
+   /// <summary>
+
+   /// ClientSinkProvider implementation.
+
+   /// </summary>
+
+   public class ClientSinkProvider: IClientChannelSinkProvider
+
+   {
+
+      #region Class Members and Defines
+
+
+
+      private IClientChannelSinkProvider m_nextProvider;
+
+
+
+      #endregion
+
+
+
+      /// <summary>
+
+      /// Constructor.
+
+      /// </summary>
+
+      public ClientSinkProvider()
+
+      {
+
+         Console.WriteLine("ClientSinkProvider instantiated");
+
+      }
+
+
+
+      /// <summary>
+
+      /// get - Return the next channel sink provider in the chain.
+
+      /// set - Specifies the next channel sink provider in the chain.
+
+      /// </summary>
+
+      public IClientChannelSinkProvider Next
+
+      {
+
+         get {return m_nextProvider;}
+
+         set {m_nextProvider = value;}
+
+      }
+
+
+
+      /// <summary>
+
+      /// Creates ClientSink and chains it to channel sink chain.
+
+      /// </summary>
+
+      /// <param name="channel">Channel provider chain</param>
+
+      /// <param name="url">Url</param>
+
+      /// <param name="remoteChannelData">Remote channel data</param>
+
+      /// <returns>SecureClientSink</returns>
+
+      public IClientChannelSink CreateSink(IChannelSender channel,
+
+         string url,
+
+         object remoteChannelData)
+
+      {
+
+         Console.WriteLine("ClientSinkProvider:CreateSink- Enter");
+
+
+
+         // Create other sinks in the chain
+
+         IClientChannelSink next = m_nextProvider.CreateSink(channel,
+
+            url,
+
+            remoteChannelData);
+
+
+
+         // Allocate SecureClientSink chained to the chain
+
+         ClientSink sink = new ClientSink(next);
+
+
+
+         Console.WriteLine("ClientSinkProvider:CreateSink- Exit");
+
+
+
+         return sink;
+
+      }
+
+   }
+
+
+
+
+
+   /// <summary>
+
+   /// ServerSink implementation.
+
+   /// </summary>
+
+   public class ServerSink: BaseChannelSinkWithProperties, IServerChannelSink
+
+   {
+
+      #region Class Members and Defines
+
+
+
+      private IServerChannelSink m_nextSink;
+
+
+
+      #endregion
+
+      /// <summary>
+
+      /// Constructor.
+
+      /// </summary>
+
+      /// <param name="next">The next sink in the chain</param>
+
+      /// <param name="secServerFactory">The factory that we must use for
+creating SecurityServers</param>
+
+      /// <param name="minMsgSecLevel">The minimum message security level
+to allow</param>
+
+      public ServerSink(IServerChannelSink next)
+
+      {
+
+         Console.WriteLine("ServerSink instantiated");
+
+
+
+         m_nextSink = next;
+
+      }
+
+
+
+      /// <summary>
+
+      /// Processes message received from peer.
+
+      /// </summary>
+
+      /// <param name="sinkStack">Server channel sink stack</param>
+
+      /// <param name="requestMsg">Request message</param>
+
+      /// <param name="requestHeaders">Request transport headers</param>
+
+      /// <param name="requestStream">Request stream</param>
+
+      /// <param name="responseMsg">Response message</param>
+
+      /// <param name="responseHeaders">Response transport headers</param>
+
+      /// <param name="responseStream">Response stream</param>
+
+      /// <returns>Indication of whether the message was processed</returns>
+
+      public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
+
+         IMessage requestMsg,
+
+         ITransportHeaders requestHeaders,
+
+         Stream requestStream,
+
+         out IMessage responseMsg,
+
+         out ITransportHeaders responseHeaders,
+
+         out Stream responseStream) 
+
+      {
+
+         Console.WriteLine("SecureServerSink.ProcessMessage- Enter");
+
+
+
+         // Initialize the output parameters
+
+         responseMsg = null;
+
+         responseHeaders = null;
+
+         responseStream = null;
+
+
+
+         // Proceed based on the contents of the "Primer" header
+
+         string primerHeaderValue = requestHeaders["Primer"] as string;
+
+         if (primerHeaderValue == "PrimerMsg")
+
+         {
+
+            // Just allocate necessary return structures
+
+            responseHeaders = (ITransportHeaders) new TransportHeaders();
+
+            responseStream = new MemoryStream();
+
+         }
+
+         else
+
+         {
+
+            // Process the message
+
+            sinkStack.Push(this, null);
+
+            ServerProcessing srvProc = m_nextSink.ProcessMessage(sinkStack,
+
+               requestMsg,
+
+               requestHeaders,
+
+               requestStream,
+
+               out responseMsg,
+
+               out responseHeaders,
+
+               out responseStream);
+
+            sinkStack.Pop(this);
+
+         }
+
+
+
+         // Add response headers
+
+         responseHeaders["TestHeader"] = "Test header value";
+
+         responseHeaders["Content-Type"] = "text/xml; charset=\"utf-8\"";
+
+
+
+         Console.WriteLine("ServerSink.ProcessMessage- Exit");
+
+
+
+         return ServerProcessing.Complete;
+
+      }
+
+
+
+      /// <summary>
+
+      /// Processes an asynchronous message destined for a peer.
+
+      /// </summary>
+
+      /// <param name="sinkStack">Server response channel sink stack</param>
+
+      /// <param name="state">????</param>
+
+      /// <param name="msg">Response message</param>
+
+      /// <param name="headers">Response transport headers</param>
+
+      /// <param name="stream">Response stream</param>
+
+      public void AsyncProcessResponse(IServerResponseChannelSinkStack
+sinkStack,
+
+         object state,
+
+         IMessage msg,
+
+         ITransportHeaders headers,
+
+         Stream stream)
+
+      {
+
+         Console.WriteLine("ServerSink.AsyncProcessResponse- Enter");
+
+
+
+         // Not implemented
+
+
+
+         // Forwarding to the stack for further processIng
+
+         sinkStack.AsyncProcessResponse(msg, headers, stream);
+
+
+
+         Console.WriteLine("ServerSink.AsyncProcessResponse- Exit");
+
+      }
+
+
+
+      /// <summary>
+
+      /// Requests a response stream from the next sink in the channel sink
+chain.
+
+      /// </summary>
+
+      /// <param name="sinkStack">Channel sink stack</param>
+
+      /// <param name="contextObject">Context object</param>
+
+      /// <param name="msg">Message</param>
+
+      /// <param name="headers">Transport Headers</param>
+
+      /// <returns>Response stream</returns>
+
+      public Stream GetResponseStream(IServerResponseChannelSinkStack
+sinkStack,
+
+         object contextObject,
+
+         IMessage msg,
+
+         ITransportHeaders headers)
+
+      {
+
+         Console.WriteLine("ServerSink.GetResponseStream- Enter");
+
+
+
+         // tbd
+
+         Stream stream = null;
+
+
+
+         Console.WriteLine("ServerSink.GetResponseStream- Exit");
+
+
+
+         return stream;
+
+      }
+
+
+
+      /// <summary>
+
+      /// Returns the next sink in the channel chain.
+
+      /// </summary>
+
+      public IServerChannelSink NextChannelSink {get {return m_nextSink;}}
+
+   }
+
+
+
+
+
+   /// <summary>
+
+   /// ServerSinkProvider implementation.
+
+   /// </summary>
+
+   public class ServerSinkProvider: IServerChannelSinkProvider
+
+   {
+
+      #region Class Members and Defines
+
+
+
+      private IServerChannelSinkProvider m_nextProvider;
+
+
+
+      #endregion
+
+
+
+      /// <summary>
+
+      /// Constructor.
+
+      /// </summary>
+
+      public ServerSinkProvider()
+
+      {
+
+         Console.WriteLine("ServerSinkProvider instantiated");
+
+      }
+
+
+
+      /// <summary>
+
+      /// get - Return the next channel sink provider in the chain.
+
+      /// set - Specifies the next channel sink provider in the chain.
+
+      /// </summary>
+
+      public IServerChannelSinkProvider Next
+
+      {
+
+         get {return m_nextProvider;}
+
+         set {m_nextProvider = value;}
+
+      }
+
+
+
+      /// <summary>
+
+      /// Creates ServerSink and chains it to channel sink chain.
+
+      /// </summary>
+
+      /// <param name="channel">Channel provider chain</param>
+
+      /// <returns>ServerSink</returns>
+
+      public IServerChannelSink CreateSink(IChannelReceiver channel)
+
+      {
+
+         Console.WriteLine("ServerSinkProvider.CreateSink- Enter");
+
+
+
+         // Create other sinks in the chain
+
+         IServerChannelSink next = m_nextProvider.CreateSink(channel);
+
+
+
+         // Allocate ServerSink chained to the chain
+
+         ServerSink sink = new ServerSink(next);
+
+
+
+         Console.WriteLine("ServerSinkProvider.CreateSink- Exit");
+
+
+
+         return sink;
+
+      }
+
+
+
+      /// <summary>
+
+      /// Does nothing.
+
+      /// </summary>
+
+      /// <param name="channelData"></param>
+
+      public void GetChannelData(IChannelDataStore channelData)
+
+      {
+
+         Console.WriteLine("ServerSinkProvider.GetChannelData- Enter");
+
+
+
+         // No need to implement
+
+
+
+         Console.WriteLine("ServerSinkProvider.GetChannelData- Exit");
+
+      }
+
+   }
+
+}
+
+
+
+The code for LinePrinter is:
+
+using System;
+
+
+
+namespace ChannelSinkTest
+
+{
+
+   /// <summary>
+
+   /// Represents a line printer.
+
+   /// </summary>
+
+   public class LinePrinter: MarshalByRefObject
+
+   {
+
+      /// <summary>
+
+      /// Constructor.
+
+      /// </summary>
+
+      public LinePrinter()
+
+      {
+
+         Console.WriteLine("LinePrinter instantiated");
+
+      }
+
+
+
+      /// <summary>
+
+      /// Prints line to console.
+
+      /// </summary>
+
+      /// <param name="line">Line to be printed</param>
+
+      public void print(string line)
+
+      {
+
+         Console.WriteLine("LinePrinter.print- called");
+
+
+
+         // Process the request
+
+         Console.WriteLine(line);
+
+      }
+
+   }
+
+}
+
+
+
+The code for Client is:
+
+using System;
+
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting.Channels.Tcp;
+using System.Collections;
+using System.Collections.Specialized;
+
+
+namespace ChannelSinkTest
+
+{
+
+	/// <summary>
+
+	/// Summary description for Class1.
+
+	/// </summary>
+
+	class Client
+
+	{
+
+      /// <summary>
+
+      /// Creates channel sink provider chain
+
+      /// </summary>
+
+      /// <returns></returns>
+
+      static IClientChannelSinkProvider CreateClientProviderChain()
+
+      {
+
+         IClientChannelSinkProvider chain = (IClientChannelSinkProvider)
+new BinaryClientFormatterSinkProvider();
+
+         IClientChannelSinkProvider sink = chain;
+
+         sink.Next = (IClientChannelSinkProvider) new ClientSinkProvider();
+
+         sink = sink.Next;
+
+         return chain;
+
+      }
+
+      /// <summary>
+
+		/// The main entry point for the application.
+
+		/// </summary>
+
+		[STAThread]
+
+		static void Main(string[] args)
+
+		{
+
+         Console.WriteLine ("Client.Main(): Client started");
+
+         // Setup a channel to request LinePrinter objects from the server
+         ListDictionary channelProperties = new ListDictionary();
+
+         IClientChannelSinkProvider clientChannelSinkProvider =
+CreateClientProviderChain();
+
+         TcpChannel channel = new TcpChannel(channelProperties,
+
+            clientChannelSinkProvider,
+
+            new BinaryServerFormatterSinkProvider());
+
+         ChannelServices.RegisterChannel(channel);
+
+         // Obtain LinePrinter object
+         Console.WriteLine("Client.Main(): Acquiring LinePrinter object");
+         LinePrinter linePrinter = (LinePrinter)
+Activator.GetObject(typeof(LinePrinter),
+            "tcp://servername:8090/LinePrinter");
+
+         // Send line to the line printer
+         linePrinter.print("This is a test line");
+
+         // Keep running until Enter is pressed
+         Console.WriteLine("Press Enter to exit...");
+         Console.ReadLine();
+		}
+
+	}
+
+}
+
+
+
+The code for Server is:
+
+using System;
+
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting.Channels.Tcp;
+using System.Collections;
+using System.Collections.Specialized;
+
+
+namespace ChannelSinkTest
+
+{
+
+	/// <summary>
+
+	/// Summary description for Class1.
+
+	/// </summary>
+
+	class Server
+
+	{
+
+      /// <summary>
+
+      /// Creates channel sink provider chain
+
+      /// </summary>
+
+      /// <returns></returns>
+
+      static IServerChannelSinkProvider CreateServerProviderChain()
+
+      {
+
+         IServerChannelSinkProvider chain = (IServerChannelSinkProvider)
+new ServerSinkProvider();
+
+         IServerChannelSinkProvider sink = chain;
+
+         sink.Next = (IServerChannelSinkProvider) new
+BinaryServerFormatterSinkProvider();            
+
+         sink = sink.Next;
+
+         return chain;
+
+      }
+
+      /// <summary>
+
+		/// The main entry point for the application.
+
+		/// </summary>
+
+		[STAThread]
+
+		static void Main(string[] args)
+
+		{
+
+         Console.WriteLine ("Server.Main(): Server started");
+
+         // Setup a channel to listen for LinePrinter requests
+         ListDictionary channelProperties = new ListDictionary();
+
+         channelProperties.Add("port", 8090);
+
+         IServerChannelSinkProvider serverChannelSinkProvider =
+CreateServerProviderChain();
+
+         TcpChannel channel = new TcpChannel(channelProperties,
+
+            new BinaryClientFormatterSinkProvider(),
+
+            serverChannelSinkProvider);
+
+         ChannelServices.RegisterChannel(channel);
+
+         // Register the LinePrinterFactory class with the remoting sub-system
+        
+RemotingConfiguration.RegisterWellKnownServiceType(typeof(LinePrinter),
+            "LinePrinter",
+            WellKnownObjectMode.Singleton);
+
+         // Keep running until Enter is pressed
+         Console.WriteLine("Listening for requests. Press Enter to exit...");
+         Console.ReadLine();
+		}
+
+	}
+
+}
+
+
+
+2. Start the Server on a Windows .NET machine, wait for it to say that it
+is listening for requests.
+ 
+3. Start the Client on a Linux box with the command "mono Client.exe"
+
+Actual Results:
+
+The Client excepts.
+
+Expected Results:
+
+The Client should print a line on the Server Console and wait for input to
+terminate.
+
+How often does this happen? 
+
+Everytime.
+
+Additional Information:
+
+eMail me if you want me to send you the code and the assemblies to the
+sample code.