[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.