Ignore test .dll and .pdb files
[mono.git] / mcs / class / System.Runtime.Remoting / System.Runtime.Remoting.Channels.Tcp / TcpMessageIO.cs
1 // System.Runtime.Remoting.Channels.Tcp.TcpMessageIO.cs
2 //
3 // Author: Lluis Sanchez Gual (lluis@ideary.com)
4 //
5 // (C) 2002 Lluis Sanchez Gual
6
7 using System;
8 using System.Runtime.Serialization;
9 using System.Runtime.Serialization.Formatters.Binary;
10 using System.Collections;
11 using System.IO;
12 using System.Text;
13 using System.Net.Sockets;
14
15 namespace System.Runtime.Remoting.Channels.Tcp 
16 {
17         enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
18
19         internal class TcpMessageIO
20         {
21                 static byte[][] _msgHeaders = 
22                           {
23                                   new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
24                                   new byte[] { 255, 255, 255, 255, 255, 255 }
25                           };
26                                                         
27                 public static int DefaultStreamBufferSize = 1000;
28
29                 // Identifies an incoming message
30                 public static MessageStatus ReceiveMessageStatus (Stream networkStream)
31                 {
32                         try
33                         {
34                                 bool[] isOnTrack = new bool[_msgHeaders.Length];
35                                 bool atLeastOneOnTrack = true;
36                                 int i = 0;
37
38                                 while (atLeastOneOnTrack)
39                                 {
40                                         atLeastOneOnTrack = false;
41                                         byte c = (byte)networkStream.ReadByte();
42                                         for (int n = 0; n<_msgHeaders.Length; n++)
43                                         {
44                                                 if (i > 0 && !isOnTrack[n]) continue;
45
46                                                 isOnTrack[n] = (c == _msgHeaders[n][i]);
47                                                 if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
48                                                 atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
49                                         }
50                                         i++;
51                                 }
52                                 return MessageStatus.Unknown;
53                         }
54                         catch (IOException)
55                         {
56                                 // Stream closed
57                                 return MessageStatus.CancelSignal;
58                         }
59                 }
60
61                 public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
62                 {
63                         if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
64
65                         // Writes the message start header
66                         byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
67                         networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
68
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 ;
73
74                         // Writes ID
75                         buffer [2] = (byte) 0;
76
77                         // Writes assemblyID????
78                         buffer [3] = (byte) 0;
79
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);
87         
88                         // Writes the message headers
89                         SendHeaders (networkStream, requestHeaders, buffer);
90
91                         // Writes the stream
92                         if (data is MemoryStream)
93                         {
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);
98                         }
99                         else
100                         {
101                                 int nread = data.Read (buffer, 0, buffer.Length);
102                                 while (nread > 0)
103                                 {
104                                         networkStream.Write (buffer, 0, nread);
105                                         nread = data.Read (buffer, 0, buffer.Length);
106                                 }
107                         }
108                 }
109
110                 private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
111                 {
112                         // Writes the headers as a sequence of strings
113                         if (networkStream != null)
114                         {
115                                 IEnumerator e = requestHeaders.GetEnumerator();
116                                 while (e.MoveNext())
117                                 {
118                                         DictionaryEntry hdr = (DictionaryEntry)e.Current;
119                                         switch (hdr.Key.ToString())
120                                         {
121                                                 case CommonTransportKeys.RequestUri: 
122                                                         buffer[0] = 4; buffer[1] = 0; buffer[2] = 1;
123                                                         networkStream.Write(buffer, 0, 3);
124                                                         break;
125                                                 case "Content-Type": 
126                                                         buffer[0] = 6; buffer[1] = 0; buffer[2] = 1;
127                                                         networkStream.Write(buffer, 0, 3);
128                                                         break;
129                                                 default: 
130                                                         buffer[0] = 1; buffer[1] = 0; buffer[2] = 1;
131                                                         networkStream.Write(buffer, 0, 3);
132                                                         SendString (networkStream, hdr.Key.ToString(), buffer);
133                                                         break;
134                                         }
135                                         networkStream.WriteByte (1);
136                                         SendString (networkStream, hdr.Value.ToString(), buffer);
137                                 }
138                         }
139                         networkStream.WriteByte (0);    // End of headers
140                         networkStream.WriteByte (0);
141                 }
142                 
143                 public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
144                 {
145                         byte headerType;
146                         headerType = (byte) networkStream.ReadByte ();
147                         networkStream.ReadByte ();
148
149                         TransportHeaders headers = new TransportHeaders ();
150
151                         while (headerType != 0)
152                         {
153                                 string key;
154                                 networkStream.ReadByte ();      // byte 1
155                                 switch (headerType)
156                                 {
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);
161                                 }
162                                 networkStream.ReadByte ();      // byte 1
163                                 headers[key] = ReceiveString (networkStream, buffer);
164
165                                 headerType = (byte) networkStream.ReadByte ();
166                                 networkStream.ReadByte ();
167                         }
168
169                         return headers;
170                 }
171                 
172                 public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
173                 {
174                         headers = null;
175
176                         if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
177
178                         // Reads header tag:  0 -> Stream with headers or 2 -> Response Stream
179                         byte head = (byte)networkStream.ReadByte();
180                         byte c = (byte)networkStream.ReadByte();
181
182                         c = (byte)networkStream.ReadByte();
183                         c = (byte)networkStream.ReadByte();
184
185                         // Gets the length of the data stream
186                         int nr = 0;
187                         while (nr < 4)
188                                 nr += networkStream.Read (buffer, nr, 4 - nr);
189
190                         int byteCount = (buffer [0] | (buffer [1] << 8) |
191                                 (buffer [2] << 16) | (buffer [3] << 24));
192
193                         // Reads the headers
194                         headers = ReceiveHeaders (networkStream, buffer);
195
196                         byte[] resultBuffer = new byte[byteCount];
197
198                         nr = 0;
199                         while (nr < byteCount)
200                                 nr += networkStream.Read (resultBuffer, nr, byteCount - nr);
201
202                         
203                         return new MemoryStream(resultBuffer);
204                 }               
205
206                 private static void SendString (Stream networkStream, string str, byte[] buffer)
207                 {
208                         // Allocates a buffer. Use the internal buffer if it is 
209                         // big enough. If not, create a new one.
210
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];
214
215                         int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
216
217                         // store number of bytes (not number of chars!)
218
219                         buffer [0] = (byte) num;
220                         buffer [1] = (byte) (num >> 8);
221                         buffer [2] = (byte) (num >> 16);
222                         buffer [3] = (byte) (num >> 24);
223
224                         // Write the string bytes
225                         networkStream.Write (buffer, 0, num + 4);
226                 }
227
228                 private static string ReceiveString (Stream networkStream, byte[] buffer)
229                 {
230                         int nr = 0;
231                         while (nr < 4)
232                                 nr += networkStream.Read (buffer, nr, 4 - nr);
233
234                         // Reads the number of bytes (not chars!)
235
236                         int byteCount = (buffer [0] | (buffer [1] << 8) |
237                                 (buffer [2] << 16) | (buffer [3] << 24));
238
239                         if (byteCount == 0) return string.Empty;
240
241                         // Allocates a buffer of the correct size. Use the
242                         // internal buffer if it is big enough
243
244                         if (byteCount > buffer.Length)
245                                 buffer = new byte[byteCount];
246
247                         // Reads the string
248
249                         nr = 0;
250                         while (nr < byteCount)
251                                 nr += networkStream.Read (buffer, nr, byteCount - nr);
252
253                         char[] chars = Encoding.UTF8.GetChars(buffer, 0, byteCount);
254         
255                         return new string(chars);
256                 }
257                 
258         }
259 }