- // ==++==
- //
- //
- // Copyright (c) 2002 Microsoft Corporation. All rights reserved.
- //
- // The use and distribution terms for this software are contained in the file
- // named license.txt, which can be found in the root of this distribution.
- // By using this software in any fashion, you are agreeing to be bound by the
- // terms of this license.
- //
- // You must not remove this notice, or any other, from this software.
- //
- //
- // ==--==
- //==========================================================================
- // File: TcpSocketManager.cs
- //
- // Summary: Provides a base for the client and server tcp socket
- // managers.
- //
- //==========================================================================
- using System;
- using System.Collections;
- using System.Globalization;
- using System.IO;
- using System.Net;
- using System.Net.Sockets;
- using System.Runtime.Remoting.Messaging;
- using System.Text;
- using System.Threading;
- namespace System.Runtime.Remoting.Channels.Tcp
- {
- // A client socket manager instance should encapsulate the socket
- // for the purpose of reading a response
- internal abstract class TcpSocketHandler : SocketHandler
- {
- private static byte[] s_protocolPreamble = Encoding.ASCII.GetBytes(".NET");
- private static byte[] s_protocolVersion1_0 = new byte[]{1,0};
- public TcpSocketHandler(Socket socket) : this(socket, null)
- {
- } // TcpSocketHandler
- public TcpSocketHandler(Socket socket, RequestQueue requestQueue) : base(socket, requestQueue)
- {
- } // TcpSocketHandler
- private void ReadAndMatchPreamble()
- {
- // make sure that the incoming data starts with the preamble
- InternalRemotingServices.RemotingAssert(
- s_protocolPreamble.Length == 4,
- "The preamble is supposed to be 4 bytes ('.NET'). Somebody changed it...");
- if (ReadAndMatchFourBytes(s_protocolPreamble) == false)
- {
- throw new RemotingException(
- CoreChannel.GetResourceString("Remoting_Tcp_ExpectingPreamble"));
- }
- } // ReadAndMatchPreamble
- protected void WritePreambleAndVersion(Stream outputStream)
- {
- outputStream.Write(s_protocolPreamble, 0, s_protocolPreamble.Length);
- outputStream.Write(s_protocolVersion1_0, 0, s_protocolVersion1_0.Length);
- } // WritePreamble
- protected void ReadVersionAndOperation(out UInt16 operation)
- {
- // check for the preamble
- ReadAndMatchPreamble();
- // Check the version number.
- byte majorVersion = (byte)ReadByte();
- byte minorVersion = (byte)ReadByte();
- if ((majorVersion != 1) || (minorVersion != 0))
- {
- throw new RemotingException(
- String.Format(
- CoreChannel.GetResourceString("Remoting_Tcp_UnknownProtocolVersion"),
- majorVersion.ToString() + "." + minorVersion.ToString()));
- }
- // Read the operation
- operation = ReadUInt16();
- } // ReadVersionAndOperation
- protected void ReadContentLength(out bool chunked, out int contentLength)
- {
- contentLength = -1;
- UInt16 header = ReadUInt16();
- if (header == TcpContentDelimiter.Chunked)
- {
- chunked = true;
- }
- else
- if (header == TcpContentDelimiter.ContentLength)
- {
- chunked = false;
- contentLength = ReadInt32();
- }
- else
- {
- throw new RemotingException(
- String.Format(
- CoreChannel.GetResourceString("Remoting_Tcp_ExpectingContentLengthHeader"),
- header.ToString()));
- }
- } // ReadContentLength
- protected void ReadToEndOfHeaders(BaseTransportHeaders headers)
- {
- bool bError = false;
- String statusPhrase = null;
- UInt16 headerType = ReadUInt16();
- while (headerType != TcpHeaders.EndOfHeaders)
- {
- if (headerType == TcpHeaders.Custom)
- {
- String headerName = ReadCountedString();
- String headerValue = ReadCountedString();
- headers[headerName] = headerValue;
- }
- else
- if (headerType == TcpHeaders.RequestUri)
- {
- ReadAndVerifyHeaderFormat("RequestUri", TcpHeaderFormat.CountedString);
- // read uri (and make sure that no channel specific data is present)
- String uri = ReadCountedString();
- String channelURI;
- String objectURI;
- channelURI = TcpChannelHelper.ParseURL(uri, out objectURI);
- if (channelURI == null)
- objectURI = uri;
- headers.RequestUri = objectURI;
- }
- else
- if (headerType == TcpHeaders.StatusCode)
- {
- ReadAndVerifyHeaderFormat("StatusCode", TcpHeaderFormat.UInt16);
- UInt16 statusCode = ReadUInt16();
- // We'll throw an exception here if there was an error. If an error
- // occurs above the transport level, the status code will still be
- // success here.
- if (statusCode != TcpStatusCode.Success)
- bError = true;
- }
- else
- if (headerType == TcpHeaders.StatusPhrase)
- {
- ReadAndVerifyHeaderFormat("StatusPhrase", TcpHeaderFormat.CountedString);
- statusPhrase = ReadCountedString();
- }
- else
- if (headerType == TcpHeaders.ContentType)
- {
- ReadAndVerifyHeaderFormat("Content-Type", TcpHeaderFormat.CountedString);
- String contentType = ReadCountedString();
- headers.ContentType = contentType;
- }
- else
- {
- // unknown header: Read header format and ignore rest of data
- byte headerFormat = (byte)ReadByte();
- switch (headerFormat)
- {
- case TcpHeaderFormat.Void: break;
- case TcpHeaderFormat.CountedString: ReadCountedString(); break;
- case TcpHeaderFormat.Byte: ReadByte(); break;
- case TcpHeaderFormat.UInt16: ReadUInt16(); break;
- case TcpHeaderFormat.Int32: ReadInt32(); break;
- default:
- {
- // unknown format
- throw new RemotingException(
- String.Format(
- CoreChannel.GetResourceString("Remoting_Tcp_UnknownHeaderType"),
- headerType, headerFormat));
- }
- } // switch (format)
- }
- // read next header token
- headerType = ReadUInt16();
- } // loop until end of headers
- // if an error occurred, throw an exception
- if (bError)
- {
- if (statusPhrase == null)
- statusPhrase = "";
- throw new RemotingException(
- String.Format(
- CoreChannel.GetResourceString("Remoting_Tcp_GenericServerError"),
- statusPhrase));
- }
- } // ReadToEndOfHeaders
- protected void WriteHeaders(ITransportHeaders headers, Stream outputStream)
- {
- IEnumerator it = null;
- BaseTransportHeaders wkHeaders = headers as BaseTransportHeaders;
- if (wkHeaders != null)
- {
- // write out well known headers
- // NOTE: RequestUri is written out elsewhere.
- if (wkHeaders.ContentType != null)
- {
- WriteContentTypeHeader(wkHeaders.ContentType, outputStream);
- }
- it = wkHeaders.GetOtherHeadersEnumerator();
- }
- else
- {
- it = headers.GetEnumerator();
- }
- // write custom headers
- if (it != null)
- {
- while (it.MoveNext())
- {
- DictionaryEntry header = (DictionaryEntry)it.Current;
- String headerName = (String)header.Key;
- if (!StringHelper.StartsWithDoubleUnderscore(headerName)) // exclude special headers
- {
- String headerValue = header.Value.ToString();
- if (wkHeaders == null)
- {
- if (String.Compare(headerName, "Content-Type", true, CultureInfo.InvariantCulture) == 0)
- {
- WriteContentTypeHeader(headerValue, outputStream);
- continue;
- }
- }
- WriteCustomHeader(headerName, headerValue, outputStream);
- }
- } // while (it.MoveNext())
- }
- // write EndOfHeaders token
- WriteUInt16(TcpHeaders.EndOfHeaders, outputStream);
- } // WriteHeaders
- private void WriteContentTypeHeader(String value, Stream outputStream)
- {
- WriteUInt16(TcpHeaders.ContentType, outputStream);
- WriteByte(TcpHeaderFormat.CountedString, outputStream);
- WriteCountedString(value, outputStream);
- } // WriteContentTypeHeader
- private void WriteCustomHeader(String name, String value, Stream outputStream)
- {
- WriteUInt16(TcpHeaders.Custom, outputStream);
- WriteCountedString(name, outputStream);
- WriteCountedString(value, outputStream);
- } // WriteCustomHeader
- protected String ReadCountedString()
- {
- // strings are formatted as follows
- // [string format (1-byte)][encoded-size (int32)][string value (encoded-size length in bytes)]
- byte strFormat = (byte)ReadByte();
- int strDataSize = ReadInt32();
- if (strDataSize > 0)
- {
- byte[] data = new byte[strDataSize];
- // SocketHander::Read waits until it reads all requested data
- Read(data, 0, strDataSize);
- switch (strFormat)
- {
- case TcpStringFormat.Unicode:
- return Encoding.Unicode.GetString(data);
- case TcpStringFormat.UTF8:
- return Encoding.UTF8.GetString(data);
- default:
- throw new RemotingException(
- String.Format(
- CoreChannel.GetResourceString("Remoting_Tcp_UnrecognizedStringFormat"),
- strFormat.ToString()));
- }
- }
- else
- {
- return null;
- }
- } // ReadCountedString
- protected void WriteCountedString(String str, Stream outputStream)
- {
- // strings are formatted as follows [string length (int32)][string value (unicode)]
- int strLength = 0;
- if (str != null)
- strLength = str.Length;
- if (strLength > 0)
- {
- byte[] strBytes = Encoding.UTF8.GetBytes(str);
- // write string format
- WriteByte(TcpStringFormat.UTF8, outputStream);
- // write string data size
- WriteInt32(strBytes.Length, outputStream);
- // write string data
- outputStream.Write(strBytes, 0, strBytes.Length);
- }
- else
- {
- // write string format
- // (just call it Unicode (doesn't matter since there is no data))
- WriteByte(TcpStringFormat.Unicode, outputStream);
- // stream data size is 0.
- WriteInt32(0, outputStream);
- }
- } // WriteCountedString
- private void ReadAndVerifyHeaderFormat(String headerName, byte expectedFormat)
- {
- byte headerFormat = (byte)ReadByte();
- if (headerFormat != expectedFormat)
- {
- throw new RemotingException(
- String.Format(
- CoreChannel.GetResourceString("Remoting_Tcp_IncorrectHeaderFormat"),
- expectedFormat, headerName));
- }
- } // ReadAndVerifyHeaderFormat
- } // TcpSocketHandler
- } // namespace System.Runtime.Remoting.Channels
TcpSocketManager.cs
最新推荐文章于 2023-08-31 16:41:59 发布