2010-04-06 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Tcp / TcpClientTransportSink.cs
blob03f4a97176cbf73a52a76ee89775274e82ddc363
1 //
2 // System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.cs
3 //
4 // Author: Dietmar Maurer (dietmar@ximian.com)
5 // Lluis Sanchez Gual (lluis@ideary.com)
6 //
7 // 2002 (C) Copyright, Ximian, Inc.
8 //
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:
18 //
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 //
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.
31 using System;
32 using System.Runtime.Remoting.Channels;
33 using System.Runtime.Remoting.Messaging;
34 using System.Collections;
35 using System.IO;
36 using System.Threading;
38 namespace System.Runtime.Remoting.Channels.Tcp
40 internal class TcpClientTransportSink : IClientChannelSink
42 string _host;
43 int _port;
45 public TcpClientTransportSink (string url)
47 string objectUri;
48 string port;
50 TcpChannel.ParseTcpURL (url, out _host, out port, out objectUri);
52 try {
53 if (port != null)
54 _port = Convert.ToInt32 (port);
55 else
56 _port = 0;
57 } catch {
58 _host = null;
59 _port = -1;
63 public IDictionary Properties
65 get
67 return null;
71 public IClientChannelSink NextChannelSink
73 get
75 // we are the last one
76 return null;
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);
86 try
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 ();
99 if (!isOneWay)
101 sinkStack.Push (this, connection);
102 ThreadPool.QueueUserWorkItem (new WaitCallback(ReadAsyncTcpMessage), sinkStack);
104 else
105 connection.Release();
107 catch
109 if (connection != null) connection.Release();
110 if (!isOneWay) throw;
114 private void ReadAsyncTcpMessage(object data)
116 // This method is called by a new thread to asynchronously
117 // read the response to a request
119 // The stack was provided as state data in QueueUserWorkItem
120 IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
122 // The first sink in the stack is this sink. Pop it and
123 // get the status data, which is the TcpConnection used to send
124 // the request
125 TcpConnection connection = (TcpConnection)stack.Pop(this);
129 ITransportHeaders responseHeaders;
131 // Read the response, blocking if necessary
132 MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
134 if (status != MessageStatus.MethodMessage)
135 throw new RemotingException ("Unknown response message from server");
137 Stream responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
139 // Free the connection, so it can be reused
140 connection.Release();
141 connection = null;
143 // Ok, proceed with the other sinks
144 stack.AsyncProcessResponse (responseHeaders, responseStream);
146 catch
148 if (connection != null) connection.Release();
149 throw;
153 public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
154 object state, ITransportHeaders headers,
155 Stream stream)
157 // Should never be called
158 throw new NotSupportedException();
161 public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
163 return null;
166 public void ProcessMessage (IMessage msg,
167 ITransportHeaders requestHeaders,
168 Stream requestStream,
169 out ITransportHeaders responseHeaders,
170 out Stream responseStream)
172 TcpConnection connection = null;
175 if (requestHeaders == null) requestHeaders = new TransportHeaders();
176 requestHeaders [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
178 // Sends the message
179 connection = TcpConnectionPool.GetConnection (_host, _port);
180 TcpMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
181 connection.Stream.Flush ();
183 // Reads the response
184 MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
186 if (status != MessageStatus.MethodMessage)
187 throw new RemotingException ("Unknown response message from server");
189 responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
191 finally
193 if (connection != null)
194 connection.Release();