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