add ISafeSerializationData
[mcs.git] / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Tcp / TcpMessageIO.cs
blob4c57d2129fb7969e1f257e5b123525078ff5efff
1 // System.Runtime.Remoting.Channels.Tcp.TcpMessageIO.cs
2 //
3 // Author: Lluis Sanchez Gual (lluis@ideary.com)
4 //
5 // (C) 2002 Lluis Sanchez Gual
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining
9 // a copy of this software and associated documentation files (the
10 // "Software"), to deal in the Software without restriction, including
11 // without limitation the rights to use, copy, modify, merge, publish,
12 // distribute, sublicense, and/or sell copies of the Software, and to
13 // permit persons to whom the Software is furnished to do so, subject to
14 // the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 using System;
29 using System.Runtime.Serialization;
30 using System.Runtime.Serialization.Formatters.Binary;
31 using System.Collections;
32 using System.IO;
33 using System.Text;
34 using System.Net.Sockets;
36 namespace System.Runtime.Remoting.Channels.Tcp
38 enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
40 internal class TcpMessageIO
42 static byte[][] _msgHeaders =
44 new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
45 new byte[] { 255, 255, 255, 255, 255, 255 }
48 public static int DefaultStreamBufferSize = 1000;
50 // Identifies an incoming message
51 public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer)
53 try {
54 StreamRead (networkStream, buffer, 6);
55 } catch (Exception ex) {
56 throw new RemotingException ("Tcp transport error.", ex);
59 try
61 bool[] isOnTrack = new bool[_msgHeaders.Length];
62 bool atLeastOneOnTrack = true;
63 int i = 0;
65 while (atLeastOneOnTrack)
67 atLeastOneOnTrack = false;
68 byte c = buffer [i];
69 for (int n = 0; n<_msgHeaders.Length; n++)
71 if (i > 0 && !isOnTrack[n]) continue;
73 isOnTrack[n] = (c == _msgHeaders[n][i]);
74 if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
75 atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
77 i++;
79 return MessageStatus.Unknown;
81 catch (Exception ex) {
82 throw new RemotingException ("Tcp transport error.", ex);
86 static bool StreamRead (Stream networkStream, byte[] buffer, int count)
88 int nr = 0;
89 do {
90 int pr = networkStream.Read (buffer, nr, count - nr);
91 if (pr == 0)
92 throw new RemotingException ("Connection closed");
93 nr += pr;
94 } while (nr < count);
95 return true;
98 public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
100 SendMessageStream (networkStream, data, requestHeaders, buffer, false);
103 public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer, bool isOneWay)
105 if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
107 // Writes the message start header
108 byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
109 networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
111 // Writes the header tag
112 // 0x0000 - request stream
113 // 0x0001 - OneWay request stream
114 // 0x0002 - response stream
115 if(requestHeaders[CommonTransportKeys.RequestUri]!=null) {
116 buffer [0] = isOneWay ? (byte) 1 : (byte) 0;
118 else {
119 buffer[0] = (byte) 2;
121 buffer [1] = (byte) 0 ;
123 // Writes ID
124 buffer [2] = (byte) 0;
126 // Writes assemblyID????
127 buffer [3] = (byte) 0;
129 // Writes the length of the stream being sent (not including the headers)
130 int num = (int)data.Length;
131 buffer [4] = (byte) num;
132 buffer [5] = (byte) (num >> 8);
133 buffer [6] = (byte) (num >> 16);
134 buffer [7] = (byte) (num >> 24);
135 networkStream.Write(buffer, 0, 8);
137 // Writes the message headers
138 SendHeaders (networkStream, requestHeaders, buffer);
140 if (data.Length == 0)
141 return;
143 // Writes the stream
144 if (data is MemoryStream)
146 // The copy of the stream can be optimized. The internal
147 // buffer of MemoryStream can be used.
148 MemoryStream memStream = (MemoryStream)data;
149 networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
151 else
153 int nread = data.Read (buffer, 0, buffer.Length);
154 while (nread > 0)
156 networkStream.Write (buffer, 0, nread);
157 nread = data.Read (buffer, 0, buffer.Length);
162 static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 };
163 static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 };
164 static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 };
165 static byte[] msgHeaderTerminator = new byte[] { 0, 0 };
167 private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
169 // Writes the headers as a sequence of strings
170 if (networkStream != null)
172 IEnumerator e = requestHeaders.GetEnumerator();
173 while (e.MoveNext())
175 DictionaryEntry hdr = (DictionaryEntry)e.Current;
176 switch (hdr.Key.ToString())
178 case CommonTransportKeys.RequestUri:
179 networkStream.Write (msgUriTransportKey, 0, 4);
180 break;
181 case "Content-Type":
182 networkStream.Write (msgContentTypeTransportKey, 0, 4);
183 break;
184 default:
185 networkStream.Write (msgDefaultTransportKey, 0, 3);
186 SendString (networkStream, hdr.Key.ToString(), buffer);
187 networkStream.WriteByte (1);
188 break;
190 SendString (networkStream, hdr.Value.ToString(), buffer);
193 networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
196 public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
198 StreamRead (networkStream, buffer, 2);
200 byte headerType = buffer [0];
201 TransportHeaders headers = new TransportHeaders ();
203 while (headerType != 0)
205 string key;
206 StreamRead (networkStream, buffer, 1); // byte 1
207 switch (headerType)
209 case 4: key = CommonTransportKeys.RequestUri; break;
210 case 6: key = "Content-Type"; break;
211 case 1: key = ReceiveString (networkStream, buffer); break;
212 default: throw new NotSupportedException ("Unknown header code: " + headerType);
214 StreamRead (networkStream, buffer, 1); // byte 1
215 headers[key] = ReceiveString (networkStream, buffer);
217 StreamRead (networkStream, buffer, 2);
218 headerType = buffer [0];
221 return headers;
224 public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
226 headers = null;
228 if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
230 // Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
231 // +
232 // Gets the length of the data stream
233 StreamRead (networkStream, buffer, 8);
235 int byteCount = (buffer [4] | (buffer [5] << 8) |
236 (buffer [6] << 16) | (buffer [7] << 24));
238 // Reads the headers
239 headers = ReceiveHeaders (networkStream, buffer);
241 if (byteCount > 0) {
242 byte[] resultBuffer = new byte[byteCount];
243 StreamRead (networkStream, resultBuffer, byteCount);
244 return new MemoryStream (resultBuffer);
245 } else {
246 return new MemoryStream ();
250 private static void SendString (Stream networkStream, string str, byte[] buffer)
252 // Allocates a buffer. Use the internal buffer if it is
253 // big enough. If not, create a new one.
255 int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
256 if (maxBytes > buffer.Length)
257 buffer = new byte[maxBytes];
259 int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
261 // store number of bytes (not number of chars!)
263 buffer [0] = (byte) num;
264 buffer [1] = (byte) (num >> 8);
265 buffer [2] = (byte) (num >> 16);
266 buffer [3] = (byte) (num >> 24);
268 // Write the string bytes
269 networkStream.Write (buffer, 0, num + 4);
272 private static string ReceiveString (Stream networkStream, byte[] buffer)
274 StreamRead (networkStream, buffer, 4);
276 // Reads the number of bytes (not chars!)
278 int byteCount = (buffer [0] | (buffer [1] << 8) |
279 (buffer [2] << 16) | (buffer [3] << 24));
281 if (byteCount == 0) return string.Empty;
283 // Allocates a buffer of the correct size. Use the
284 // internal buffer if it is big enough
286 if (byteCount > buffer.Length)
287 buffer = new byte[byteCount];
289 // Reads the string
291 StreamRead (networkStream, buffer, byteCount);
292 char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
294 return new string (chars);