2 // System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.cs
4 // Author: Dietmar Maurer (dietmar@ximian.com)
5 // Lluis Sanchez Gual (lluis@ideary.com)
7 // 2002 (C) Copyright, Ximian, Inc.
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Runtime.Remoting.Channels;
33 using System.Runtime.Remoting.Messaging;
34 using System.Collections;
36 using System.Threading;
38 namespace System.Runtime.Remoting.Channels.Tcp
40 internal class TcpClientTransportSink : IClientChannelSink
45 public TcpClientTransportSink (string url)
50 TcpChannel.ParseTcpURL (url, out _host, out port, out objectUri);
54 _port = Convert.ToInt32 (port);
63 public IDictionary Properties
71 public IClientChannelSink NextChannelSink
75 // we are the last one
80 public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
81 ITransportHeaders headers, Stream requestStream)
83 TcpConnection connection = null;
84 bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
88 if (headers == null) headers = new TransportHeaders();
89 headers [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
91 // Sends the stream using a connection from the pool
92 // and creates a WorkItem that will wait for the
93 // response of the server
95 connection = TcpConnectionPool.GetConnection (_host, _port);
96 TcpMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer, isOneWay);
97 connection.Stream.Flush ();
101 sinkStack.Push (this, connection);
102 ThreadPool.QueueUserWorkItem (new WaitCallback(data => {
104 ReadAsyncTcpMessage (data);
109 connection.Release();
113 if (connection != null) connection.Release();
114 if (!isOneWay) throw;
118 private void ReadAsyncTcpMessage(object data)
120 // This method is called by a new thread to asynchronously
121 // read the response to a request
123 // The stack was provided as state data in QueueUserWorkItem
124 IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
126 // The first sink in the stack is this sink. Pop it and
127 // get the status data, which is the TcpConnection used to send
129 TcpConnection connection = (TcpConnection)stack.Pop(this);
133 ITransportHeaders responseHeaders;
135 // Read the response, blocking if necessary
136 MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
138 if (status != MessageStatus.MethodMessage)
139 throw new RemotingException ("Unknown response message from server");
141 Stream responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
143 // Free the connection, so it can be reused
144 connection.Release();
147 // Ok, proceed with the other sinks
148 stack.AsyncProcessResponse (responseHeaders, responseStream);
152 if (connection != null) connection.Release();
157 public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
158 object state, ITransportHeaders headers,
161 // Should never be called
162 throw new NotSupportedException();
165 public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
170 public void ProcessMessage (IMessage msg,
171 ITransportHeaders requestHeaders,
172 Stream requestStream,
173 out ITransportHeaders responseHeaders,
174 out Stream responseStream)
176 TcpConnection connection = null;
179 if (requestHeaders == null) requestHeaders = new TransportHeaders();
180 requestHeaders [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
183 connection = TcpConnectionPool.GetConnection (_host, _port);
184 TcpMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
185 connection.Stream.Flush ();
187 // Reads the response
188 MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
190 if (status != MessageStatus.MethodMessage)
191 throw new RemotingException ("Unknown response message from server");
193 responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
197 if (connection != null)
198 connection.Release();