2 // Mono.Remoting.Channels.Unix.UnixMessageIO.cs
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
6 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.Runtime
.Serialization
;
31 using System
.Runtime
.Serialization
.Formatters
.Binary
;
32 using System
.Collections
;
35 using System
.Net
.Sockets
;
36 using System
.Runtime
.Remoting
.Channels
;
37 using System
.Runtime
.Remoting
;
39 namespace Mono
.Remoting
.Channels
.Unix
41 enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
43 internal class UnixMessageIO
45 static byte[][] _msgHeaders
=
47 new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 }
,
48 new byte[] { 255, 255, 255, 255, 255, 255 }
51 public static int DefaultStreamBufferSize
= 1000;
53 // Identifies an incoming message
54 public static MessageStatus
ReceiveMessageStatus (Stream networkStream
, byte[] buffer
)
57 StreamRead (networkStream
, buffer
, 6);
58 } catch (Exception ex
) {
59 throw new RemotingException ("Unix transport error.", ex
);
64 bool[] isOnTrack
= new bool[_msgHeaders
.Length
];
65 bool atLeastOneOnTrack
= true;
68 while (atLeastOneOnTrack
)
70 atLeastOneOnTrack
= false;
72 for (int n
= 0; n
<_msgHeaders
.Length
; n
++)
74 if (i
> 0 && !isOnTrack
[n
]) continue;
76 isOnTrack
[n
] = (c
== _msgHeaders
[n
][i
]);
77 if (isOnTrack
[n
] && (i
== _msgHeaders
[n
].Length
-1)) return (MessageStatus
) n
;
78 atLeastOneOnTrack
= atLeastOneOnTrack
|| isOnTrack
[n
];
82 return MessageStatus
.Unknown
;
84 catch (Exception ex
) {
85 throw new RemotingException ("Unix transport error.", ex
);
89 static bool StreamRead (Stream networkStream
, byte[] buffer
, int count
)
93 int pr
= networkStream
.Read (buffer
, nr
, count
- nr
);
95 throw new RemotingException ("Connection closed");
101 public static void SendMessageStream (Stream networkStream
, Stream data
, ITransportHeaders requestHeaders
, byte[] buffer
)
103 if (buffer
== null) buffer
= new byte[DefaultStreamBufferSize
];
105 // Writes the message start header
106 byte[] dotnetHeader
= _msgHeaders
[(int) MessageStatus
.MethodMessage
];
107 networkStream
.Write(dotnetHeader
, 0, dotnetHeader
.Length
);
109 // Writes header tag (0x0000 if request stream, 0x0002 if response stream)
110 if(requestHeaders
["__RequestUri"]!=null) buffer
[0] = (byte) 0;
111 else buffer
[0] = (byte) 2;
112 buffer
[1] = (byte) 0 ;
115 buffer
[2] = (byte) 0;
117 // Writes assemblyID????
118 buffer
[3] = (byte) 0;
120 // Writes the length of the stream being sent (not including the headers)
121 int num
= (int)data
.Length
;
122 buffer
[4] = (byte) num
;
123 buffer
[5] = (byte) (num
>> 8);
124 buffer
[6] = (byte) (num
>> 16);
125 buffer
[7] = (byte) (num
>> 24);
126 networkStream
.Write(buffer
, 0, 8);
128 // Writes the message headers
129 SendHeaders (networkStream
, requestHeaders
, buffer
);
132 if (data
is MemoryStream
)
134 // The copy of the stream can be optimized. The internal
135 // buffer of MemoryStream can be used.
136 MemoryStream memStream
= (MemoryStream
)data
;
137 networkStream
.Write (memStream
.GetBuffer(), 0, (int)memStream
.Length
);
141 int nread
= data
.Read (buffer
, 0, buffer
.Length
);
144 networkStream
.Write (buffer
, 0, nread
);
145 nread
= data
.Read (buffer
, 0, buffer
.Length
);
150 static byte[] msgUriTransportKey
= new byte[] { 4, 0, 1, 1 }
;
151 static byte[] msgContentTypeTransportKey
= new byte[] { 6, 0, 1, 1 }
;
152 static byte[] msgDefaultTransportKey
= new byte[] { 1, 0, 1 }
;
153 static byte[] msgHeaderTerminator
= new byte[] { 0, 0 }
;
155 private static void SendHeaders(Stream networkStream
, ITransportHeaders requestHeaders
, byte[] buffer
)
157 // Writes the headers as a sequence of strings
158 if (networkStream
!= null)
160 IEnumerator e
= requestHeaders
.GetEnumerator();
163 DictionaryEntry hdr
= (DictionaryEntry
)e
.Current
;
164 switch (hdr
.Key
.ToString())
167 networkStream
.Write (msgUriTransportKey
, 0, 4);
170 networkStream
.Write (msgContentTypeTransportKey
, 0, 4);
173 networkStream
.Write (msgDefaultTransportKey
, 0, 3);
174 SendString (networkStream
, hdr
.Key
.ToString(), buffer
);
175 networkStream
.WriteByte (1);
178 SendString (networkStream
, hdr
.Value
.ToString(), buffer
);
181 networkStream
.Write (msgHeaderTerminator
, 0, 2); // End of headers
184 public static ITransportHeaders
ReceiveHeaders (Stream networkStream
, byte[] buffer
)
186 StreamRead (networkStream
, buffer
, 2);
188 byte headerType
= buffer
[0];
189 TransportHeaders headers
= new TransportHeaders ();
191 while (headerType
!= 0)
194 StreamRead (networkStream
, buffer
, 1); // byte 1
197 case 4: key
= "__RequestUri"; break;
198 case 6: key
= "Content-Type"; break;
199 case 1: key
= ReceiveString (networkStream
, buffer
); break;
200 default: throw new NotSupportedException ("Unknown header code: " + headerType
);
202 StreamRead (networkStream
, buffer
, 1); // byte 1
203 headers
[key
] = ReceiveString (networkStream
, buffer
);
205 StreamRead (networkStream
, buffer
, 2);
206 headerType
= buffer
[0];
212 public static Stream
ReceiveMessageStream (Stream networkStream
, out ITransportHeaders headers
, byte[] buffer
)
216 if (buffer
== null) buffer
= new byte[DefaultStreamBufferSize
];
218 // Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
220 // Gets the length of the data stream
221 StreamRead (networkStream
, buffer
, 8);
223 int byteCount
= (buffer
[4] | (buffer
[5] << 8) |
224 (buffer
[6] << 16) | (buffer
[7] << 24));
227 headers
= ReceiveHeaders (networkStream
, buffer
);
229 byte[] resultBuffer
= new byte[byteCount
];
230 StreamRead (networkStream
, resultBuffer
, byteCount
);
232 return new MemoryStream (resultBuffer
);
235 private static void SendString (Stream networkStream
, string str
, byte[] buffer
)
237 // Allocates a buffer. Use the internal buffer if it is
238 // big enough. If not, create a new one.
240 int maxBytes
= Encoding
.UTF8
.GetMaxByteCount(str
.Length
)+4; //+4 bytes for storing the string length
241 if (maxBytes
> buffer
.Length
)
242 buffer
= new byte[maxBytes
];
244 int num
= Encoding
.UTF8
.GetBytes (str
, 0, str
.Length
, buffer
, 4);
246 // store number of bytes (not number of chars!)
248 buffer
[0] = (byte) num
;
249 buffer
[1] = (byte) (num
>> 8);
250 buffer
[2] = (byte) (num
>> 16);
251 buffer
[3] = (byte) (num
>> 24);
253 // Write the string bytes
254 networkStream
.Write (buffer
, 0, num
+ 4);
257 private static string ReceiveString (Stream networkStream
, byte[] buffer
)
259 StreamRead (networkStream
, buffer
, 4);
261 // Reads the number of bytes (not chars!)
263 int byteCount
= (buffer
[0] | (buffer
[1] << 8) |
264 (buffer
[2] << 16) | (buffer
[3] << 24));
266 if (byteCount
== 0) return string.Empty
;
268 // Allocates a buffer of the correct size. Use the
269 // internal buffer if it is big enough
271 if (byteCount
> buffer
.Length
)
272 buffer
= new byte[byteCount
];
276 StreamRead (networkStream
, buffer
, byteCount
);
277 char[] chars
= Encoding
.UTF8
.GetChars (buffer
, 0, byteCount
);
279 return new string (chars
);