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