1 // System.Runtime.Remoting.Channels.Tcp.TcpMessageIO.cs
3 // Author: Lluis Sanchez Gual (lluis@ideary.com)
5 // (C) 2002 Lluis Sanchez Gual
8 using System.Runtime.Serialization;
9 using System.Runtime.Serialization.Formatters.Binary;
10 using System.Collections;
13 using System.Net.Sockets;
15 namespace System.Runtime.Remoting.Channels.Tcp
17 enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
19 internal class TcpMessageIO
21 static byte[][] _msgHeaders =
23 new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
24 new byte[] { 255, 255, 255, 255, 255, 255 }
27 public static int DefaultStreamBufferSize = 1000;
29 // Identifies an incoming message
30 public static MessageStatus ReceiveMessageStatus (Stream networkStream)
34 bool[] isOnTrack = new bool[_msgHeaders.Length];
35 bool atLeastOneOnTrack = true;
38 while (atLeastOneOnTrack)
40 atLeastOneOnTrack = false;
41 byte c = (byte)networkStream.ReadByte();
42 for (int n = 0; n<_msgHeaders.Length; n++)
44 if (i > 0 && !isOnTrack[n]) continue;
46 isOnTrack[n] = (c == _msgHeaders[n][i]);
47 if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
48 atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
52 return MessageStatus.Unknown;
57 return MessageStatus.CancelSignal;
61 public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
63 if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
65 // Writes the message start header
66 byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
67 networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
69 // Writes header tag (0x0000 if request stream, 0x0002 if response stream)
70 if(requestHeaders[CommonTransportKeys.RequestUri]!=null) buffer [0] = (byte) 0;
71 else buffer[0] = (byte) 2;
72 buffer [1] = (byte) 0 ;
75 buffer [2] = (byte) 0;
77 // Writes assemblyID????
78 buffer [3] = (byte) 0;
80 // Writes the length of the stream being sent (not including the headers)
81 int num = (int)data.Length;
82 buffer [4] = (byte) num;
83 buffer [5] = (byte) (num >> 8);
84 buffer [6] = (byte) (num >> 16);
85 buffer [7] = (byte) (num >> 24);
86 networkStream.Write(buffer, 0, 8);
88 // Writes the message headers
89 SendHeaders (networkStream, requestHeaders, buffer);
92 if (data is MemoryStream)
94 // The copy of the stream can be optimized. The internal
95 // buffer of MemoryStream can be used.
96 MemoryStream memStream = (MemoryStream)data;
97 networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
101 int nread = data.Read (buffer, 0, buffer.Length);
104 networkStream.Write (buffer, 0, nread);
105 nread = data.Read (buffer, 0, buffer.Length);
110 private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
112 // Writes the headers as a sequence of strings
113 if (networkStream != null)
115 IEnumerator e = requestHeaders.GetEnumerator();
118 DictionaryEntry hdr = (DictionaryEntry)e.Current;
119 switch (hdr.Key.ToString())
121 case CommonTransportKeys.RequestUri:
122 buffer[0] = 4; buffer[1] = 0; buffer[2] = 1;
123 networkStream.Write(buffer, 0, 3);
126 buffer[0] = 6; buffer[1] = 0; buffer[2] = 1;
127 networkStream.Write(buffer, 0, 3);
130 buffer[0] = 1; buffer[1] = 0; buffer[2] = 1;
131 networkStream.Write(buffer, 0, 3);
132 SendString (networkStream, hdr.Key.ToString(), buffer);
135 networkStream.WriteByte (1);
136 SendString (networkStream, hdr.Value.ToString(), buffer);
139 networkStream.WriteByte (0); // End of headers
140 networkStream.WriteByte (0);
143 public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
146 headerType = (byte) networkStream.ReadByte ();
147 networkStream.ReadByte ();
149 TransportHeaders headers = new TransportHeaders ();
151 while (headerType != 0)
154 networkStream.ReadByte (); // byte 1
157 case 4: key = CommonTransportKeys.RequestUri; break;
158 case 6: key = "Content-Type"; break;
159 case 1: key = ReceiveString (networkStream, buffer); break;
160 default: throw new NotSupportedException ("Unknown header code: " + headerType);
162 networkStream.ReadByte (); // byte 1
163 headers[key] = ReceiveString (networkStream, buffer);
165 headerType = (byte) networkStream.ReadByte ();
166 networkStream.ReadByte ();
172 public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
176 if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
178 // Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
179 byte head = (byte)networkStream.ReadByte();
180 byte c = (byte)networkStream.ReadByte();
182 c = (byte)networkStream.ReadByte();
183 c = (byte)networkStream.ReadByte();
185 // Gets the length of the data stream
188 nr += networkStream.Read (buffer, nr, 4 - nr);
190 int byteCount = (buffer [0] | (buffer [1] << 8) |
191 (buffer [2] << 16) | (buffer [3] << 24));
194 headers = ReceiveHeaders (networkStream, buffer);
196 byte[] resultBuffer = new byte[byteCount];
199 while (nr < byteCount)
200 nr += networkStream.Read (resultBuffer, nr, byteCount - nr);
203 return new MemoryStream(resultBuffer);
206 private static void SendString (Stream networkStream, string str, byte[] buffer)
208 // Allocates a buffer. Use the internal buffer if it is
209 // big enough. If not, create a new one.
211 int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
212 if (maxBytes > buffer.Length)
213 buffer = new byte[maxBytes];
215 int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
217 // store number of bytes (not number of chars!)
219 buffer [0] = (byte) num;
220 buffer [1] = (byte) (num >> 8);
221 buffer [2] = (byte) (num >> 16);
222 buffer [3] = (byte) (num >> 24);
224 // Write the string bytes
225 networkStream.Write (buffer, 0, num + 4);
228 private static string ReceiveString (Stream networkStream, byte[] buffer)
232 nr += networkStream.Read (buffer, nr, 4 - nr);
234 // Reads the number of bytes (not chars!)
236 int byteCount = (buffer [0] | (buffer [1] << 8) |
237 (buffer [2] << 16) | (buffer [3] << 24));
239 if (byteCount == 0) return string.Empty;
241 // Allocates a buffer of the correct size. Use the
242 // internal buffer if it is big enough
244 if (byteCount > buffer.Length)
245 buffer = new byte[byteCount];
250 while (nr < byteCount)
251 nr += networkStream.Read (buffer, nr, byteCount - nr);
253 char[] chars = Encoding.UTF8.GetChars(buffer, 0, byteCount);
255 return new string(chars);