1 //
2 // Mono.Remoting.Channels.Unix.UnixMessageIO.cs
3 //
4 // Author: Lluis Sanchez Gual (lluis@ideary.com)
5 //
6 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
7 
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27 //
28 
29 using System;
30 using System.Runtime.Serialization;
31 using System.Runtime.Serialization.Formatters.Binary;
32 using System.Collections;
33 using System.IO;
34 using System.Text;
35 using System.Net.Sockets;
36 using System.Runtime.Remoting.Channels;
37 using System.Runtime.Remoting;
38 
39 namespace Mono.Remoting.Channels.Unix
40 {
41 	enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
42 
43 	internal class UnixMessageIO
44 	{
45 		static byte[][] _msgHeaders =
46 			  {
47 				  new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
48 				  new byte[] { 255, 255, 255, 255, 255, 255 }
49 			  };
50 
51 		public static int DefaultStreamBufferSize = 1000;
52 
53 		// Identifies an incoming message
ReceiveMessageStatus(Stream networkStream, byte[] buffer)54 		public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer)
55 		{
56 			try {
57 				StreamRead (networkStream, buffer, 6);
58 			} catch (Exception ex) {
59 				throw new RemotingException ("Unix transport error.", ex);
60 			}
61 
62 			try
63 			{
64 				bool[] isOnTrack = new bool[_msgHeaders.Length];
65 				bool atLeastOneOnTrack = true;
66 				int i = 0;
67 
68 				while (atLeastOneOnTrack)
69 				{
70 					atLeastOneOnTrack = false;
71 					byte c = buffer [i];
72 					for (int n = 0; n<_msgHeaders.Length; n++)
73 					{
74 						if (i > 0 && !isOnTrack[n]) continue;
75 
76 						isOnTrack[n] = (c == _msgHeaders[n][i]);
77 						if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
78 						atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
79 					}
80 					i++;
81 				}
82 				return MessageStatus.Unknown;
83 			}
84 			catch (Exception ex) {
85 				throw new RemotingException ("Unix transport error.", ex);
86 			}
87 		}
88 
StreamRead(Stream networkStream, byte[] buffer, int count)89 		static bool StreamRead (Stream networkStream, byte[] buffer, int count)
90 		{
91 			int nr = 0;
92 			do {
93 				int pr = networkStream.Read (buffer, nr, count - nr);
94 				if (pr == 0)
95 					throw new RemotingException ("Connection closed");
96 				nr += pr;
97 			} while (nr < count);
98 			return true;
99 		}
100 
SendMessageStream(Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)101 		public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
102 		{
103 			if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
104 
105 			// Writes the message start header
106 			byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
107 			networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
108 
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 ;
113 
114 			// Writes ID
115 			buffer [2] = (byte) 0;
116 
117 			// Writes assemblyID????
118 			buffer [3] = (byte) 0;
119 
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);
127 
128 			// Writes the message headers
129 			SendHeaders (networkStream, requestHeaders, buffer);
130 
131 			// Writes the stream
132 			if (data is MemoryStream)
133 			{
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);
138 			}
139 			else
140 			{
141 				int nread = data.Read (buffer, 0, buffer.Length);
142 				while (nread > 0)
143 				{
144 					networkStream.Write (buffer, 0, nread);
145 					nread = data.Read (buffer, 0, buffer.Length);
146 				}
147 			}
148 		}
149 
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 };
154 
SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)155 		private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
156 		{
157 			// Writes the headers as a sequence of strings
158 			if (networkStream != null)
159 			{
160 				IEnumerator e = requestHeaders.GetEnumerator();
161 				while (e.MoveNext())
162 				{
163 					DictionaryEntry hdr = (DictionaryEntry)e.Current;
164 					switch (hdr.Key.ToString())
165 					{
166 						case "__RequestUri":
167 							networkStream.Write (msgUriTransportKey, 0, 4);
168 							break;
169 						case "Content-Type":
170 							networkStream.Write (msgContentTypeTransportKey, 0, 4);
171 							break;
172 						default:
173 							networkStream.Write (msgDefaultTransportKey, 0, 3);
174 							SendString (networkStream, hdr.Key.ToString(), buffer);
175 							networkStream.WriteByte (1);
176 							break;
177 					}
178 					SendString (networkStream, hdr.Value.ToString(), buffer);
179 				}
180 			}
181 			networkStream.Write (msgHeaderTerminator, 0, 2);	// End of headers
182 		}
183 
ReceiveHeaders(Stream networkStream, byte[] buffer)184 		public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
185 		{
186 			StreamRead (networkStream, buffer, 2);
187 
188 			byte headerType = buffer [0];
189 			TransportHeaders headers = new TransportHeaders ();
190 
191 			while (headerType != 0)
192 			{
193 				string key;
194 				StreamRead (networkStream, buffer, 1);	// byte 1
195 				switch (headerType)
196 				{
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);
201 				}
202 				StreamRead (networkStream, buffer, 1);	// byte 1
203 				headers[key] = ReceiveString (networkStream, buffer);
204 
205 				StreamRead (networkStream, buffer, 2);
206 				headerType = buffer [0];
207 			}
208 
209 			return headers;
210 		}
211 
ReceiveMessageStream(Stream networkStream, out ITransportHeaders headers, byte[] buffer)212 		public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
213 		{
214 			headers = null;
215 
216 			if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
217 
218 			// Reads header tag:  0 -> Stream with headers or 2 -> Response Stream
219 			// +
220 			// Gets the length of the data stream
221 			StreamRead (networkStream, buffer, 8);
222 
223 			int byteCount = (buffer [4] | (buffer [5] << 8) |
224 				(buffer [6] << 16) | (buffer [7] << 24));
225 
226 			// Reads the headers
227 			headers = ReceiveHeaders (networkStream, buffer);
228 
229 			byte[] resultBuffer = new byte[byteCount];
230 			StreamRead (networkStream, resultBuffer, byteCount);
231 
232 			return new MemoryStream (resultBuffer);
233 		}
234 
SendString(Stream networkStream, string str, byte[] buffer)235 		private static void SendString (Stream networkStream, string str, byte[] buffer)
236 		{
237 			// Allocates a buffer. Use the internal buffer if it is
238 			// big enough. If not, create a new one.
239 
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];
243 
244 			int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
245 
246 			// store number of bytes (not number of chars!)
247 
248 			buffer [0] = (byte) num;
249 			buffer [1] = (byte) (num >> 8);
250 			buffer [2] = (byte) (num >> 16);
251 			buffer [3] = (byte) (num >> 24);
252 
253 			// Write the string bytes
254 			networkStream.Write (buffer, 0, num + 4);
255 		}
256 
ReceiveString(Stream networkStream, byte[] buffer)257 		private static string ReceiveString (Stream networkStream, byte[] buffer)
258 		{
259 			StreamRead (networkStream, buffer, 4);
260 
261 			// Reads the number of bytes (not chars!)
262 
263 			int byteCount = (buffer [0] | (buffer [1] << 8) |
264 				(buffer [2] << 16) | (buffer [3] << 24));
265 
266 			if (byteCount == 0) return string.Empty;
267 
268 			// Allocates a buffer of the correct size. Use the
269 			// internal buffer if it is big enough
270 
271 			if (byteCount > buffer.Length)
272 				buffer = new byte[byteCount];
273 
274 			// Reads the string
275 
276 			StreamRead (networkStream, buffer, byteCount);
277 			char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
278 
279 			return new string (chars);
280 		}
281 
282 	}
283 }
284