2005-07-28 Lluis Sanchez Gual <lluis@novell.com>
[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 [CommonTransportKeys.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(ReadAsyncUnixMessage), sinkStack);
91                                 }
92                                 else
93                                         connection.Release();
94                         }
95                         catch
96                         {
97                                 if (connection != null) connection.Release();
98                                 if (!isOneWay) throw;
99                         }
100                 }
101
102                 private void ReadAsyncUnixMessage(object data)
103                 {
104                         // This method is called by a new thread to asynchronously
105                         // read the response to a request
106
107                         // The stack was provided as state data in QueueUserWorkItem
108                         IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
109
110                         // The first sink in the stack is this sink. Pop it and
111                         // get the status data, which is the UnixConnection used to send
112                         // the request
113                         UnixConnection connection = (UnixConnection)stack.Pop(this);
114
115                         try
116                         {
117                                 ITransportHeaders responseHeaders;
118
119                                 // Read the response, blocking if necessary
120                                 MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
121
122                                 if (status != MessageStatus.MethodMessage)
123                                         throw new RemotingException ("Unknown response message from server");
124
125                                 Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
126
127                                 // Free the connection, so it can be reused
128                                 connection.Release();
129                                 connection = null;
130
131                                 // Ok, proceed with the other sinks
132                                 stack.AsyncProcessResponse (responseHeaders, responseStream);
133                         }
134                         catch
135                         {
136                                 if (connection != null) connection.Release();
137                                 throw;
138                         }
139                 }
140         
141                 public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
142                         object state, ITransportHeaders headers,
143                         Stream stream)
144                 {
145                         // Should never be called
146                         throw new NotSupportedException();
147                 }
148
149                 public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
150                 {
151                         return null;
152                 }
153                 
154                 public void ProcessMessage (IMessage msg,
155                         ITransportHeaders requestHeaders,
156                         Stream requestStream,
157                         out ITransportHeaders responseHeaders,
158                         out Stream responseStream)
159                 {
160                         UnixConnection connection = null;
161                         try
162                         {
163                                 if (requestHeaders == null) requestHeaders = new TransportHeaders();
164                                 requestHeaders [CommonTransportKeys.RequestUri] = ((IMethodMessage)msg).Uri;
165                                 
166                                 // Sends the message
167                                 connection = UnixConnectionPool.GetConnection (_path);
168                                 UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
169                                 connection.Stream.Flush ();
170
171                                 // Reads the response
172                                 MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
173
174                                 if (status != MessageStatus.MethodMessage)
175                                         throw new RemotingException ("Unknown response message from server");
176
177                                 responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
178                         }
179                         finally
180                         {
181                                 if (connection != null) 
182                                         connection.Release();
183                         }
184                 }
185
186         }
187
188
189 }