8b058db0ddd86b26e957e30a50a9a949470aed62
[mono.git] / mcs / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Tcp / TcpClientTransportSink.cs
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 //\r
9
10 //
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.
29 //
30 \r
31 using System;\r
32 using System.Runtime.Remoting.Channels;\r
33 using System.Runtime.Remoting.Messaging;\r
34 using System.Collections;\r
35 using System.IO;\r
36 using System.Threading;\r
37 \r
38 namespace System.Runtime.Remoting.Channels.Tcp\r
39 {\r
40         internal class TcpClientTransportSink : IClientChannelSink
41         {
42                 string _host;
43                 string _url;
44                 int _port;
45                 
46                 public TcpClientTransportSink (string url)
47                 {
48                         string objectUri;
49                         _host = TcpChannel.ParseTcpURL (url, out objectUri, out _port);
50                         _url = url;
51                 }
52
53                 public IDictionary Properties
54                 {
55                         get \r
56                         {
57                                 return null;
58                         }
59                 }
60
61                 public IClientChannelSink NextChannelSink
62                 {
63                         get \r
64                         {
65                                 // we are the last one
66                                 return null;
67                         }
68                 }
69
70                 public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
71                         ITransportHeaders headers, Stream requestStream)
72                 {
73                         TcpConnection connection = null;
74                         bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
75
76                         try
77                         {
78                                 if (headers == null) headers = new TransportHeaders();
79                                 headers [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
80                                 
81                                 // Sends the stream using a connection from the pool
82                                 // and creates a WorkItem that will wait for the
83                                 // response of the server
84
85                                 connection = TcpConnectionPool.GetConnection (_host, _port);
86                                 TcpMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
87                                 connection.Stream.Flush ();
88
89                                 if (!isOneWay) 
90                                 {
91                                         sinkStack.Push (this, connection);
92                                         ThreadPool.QueueUserWorkItem (new WaitCallback(ReadAsyncTcpMessage), sinkStack);
93                                 }
94                                 else
95                                         connection.Release();
96                         }
97                         catch
98                         {
99                                 if (connection != null) connection.Release();
100                                 if (!isOneWay) throw;
101                         }
102                 }
103
104                 private void ReadAsyncTcpMessage(object data)
105                 {
106                         // This method is called by a new thread to asynchronously
107                         // read the response to a request
108
109                         // The stack was provided as state data in QueueUserWorkItem
110                         IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
111
112                         // The first sink in the stack is this sink. Pop it and
113                         // get the status data, which is the TcpConnection used to send
114                         // the request
115                         TcpConnection connection = (TcpConnection)stack.Pop(this);
116
117                         try
118                         {
119                                 ITransportHeaders responseHeaders;
120
121                                 // Read the response, blocking if necessary
122                                 MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
123
124                                 if (status != MessageStatus.MethodMessage)
125                                         throw new RemotingException ("Unknown response message from server");
126
127                                 Stream responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
128
129                                 // Free the connection, so it can be reused
130                                 connection.Release();
131                                 connection = null;
132
133                                 // Ok, proceed with the other sinks
134                                 stack.AsyncProcessResponse (responseHeaders, responseStream);
135                         }
136                         catch
137                         {
138                                 if (connection != null) connection.Release();
139                                 throw;
140                         }
141                 }
142         
143                 public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
144                         object state, ITransportHeaders headers,
145                         Stream stream)
146                 {
147                         // Should never be called
148                         throw new NotSupportedException();
149                 }
150
151                 public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
152                 {
153                         return null;
154                 }
155                 
156                 public void ProcessMessage (IMessage msg,
157                         ITransportHeaders requestHeaders,
158                         Stream requestStream,
159                         out ITransportHeaders responseHeaders,
160                         out Stream responseStream)
161                 {
162                         TcpConnection connection = null;
163                         try
164                         {
165                                 if (requestHeaders == null) requestHeaders = new TransportHeaders();
166                                 requestHeaders [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
167                                 
168                                 // Sends the message
169                                 connection = TcpConnectionPool.GetConnection (_host, _port);
170                                 TcpMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
171                                 connection.Stream.Flush ();
172
173                                 // Reads the response
174                                 MessageStatus status = TcpMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
175
176                                 if (status != MessageStatus.MethodMessage)
177                                         throw new RemotingException ("Unknown response message from server");
178
179                                 responseStream = TcpMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
180                         }
181                         finally
182                         {
183                                 if (connection != null) 
184                                         connection.Release();
185                         }
186                 }
187
188         }
189
190 \r
191 }\r