Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version
Go to top

Secure Web Services via TCP/IP

, 30 May 2003
Describes an approach for delivery of Soap Messages serialised using ASP.NET Web Client Services over TCP/IP
wsaltroute2.zip
ArgosAPIExtensions
Bin
Client
ArgosAPIExtensions.dll
WSAltRouteTest.exe
WSIPTransports.dll
Server
WebServices
WSAltRouteArgos
bin
ArgosAPIExtensions.dll
ArgosAPIExtensions.pdb
WSAltRouteArgos.dll
WSAltRouteArgos.pdb
Global.asax
WSAltRouteArgos.csproj.webinfo
WSAltRouteArgos.vsdisco
WSAltRouteBEFake.exe
WSAltRouteTest
App.ico
Web References
ArgosTrinketService
Reference.map
Service1.disco
Service1.wsdl
WSAltRouteBEFake
App.ico
WSAltTransports2
WSQTransports.dll
AsyncHelper.dll
using System;
using System.IO;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Web.Services.Protocols;


namespace WSAltTransports
{
	/// <summary>WSAltTransports.IPRequestCreator</summary>
	/// <author>SGregory</author>
	/// <date>02 January 2003</date>
	/// <remarks>Creation Factory for IP-style WebRequests</remarks>
	public sealed class IPRequestCreator : IWebRequestCreate
	{
		/// <summary>WSAltTransports.IPRequestCreator.Create</summary>
		/// <author>SGregory</author>
		/// <date>02 January 2003</date>
		/// <remarks>Creates an IPWebRequest object</remarks>
		/// <param name="Uri" type="System.Uri">URI indicating endpoint</param>
		/// <returns type="System.Net.WebRequest">IPWebRequest object</returns>
		public WebRequest Create(
			Uri Uri)
		{
			// Create a new request
			return new IPWebRequest(
				Uri);
		}
	}


	/// <summary>WSAltTransports.IPWebRequest</summary>
	/// <author>SGregory</author>
	/// <date>16 January 2003</date>
	/// <remarks>This class handles the specific implementation of the Sockets transport</remarks>
	public sealed class IPWebRequest : MyBaseWebRequest
	{
		/// <summary>WSAltTransports.IPWebRequest</summary>
		/// <author>SGregory</author>
		/// <date>02 January 2003</date>
		/// <remarks>This is the entry point for all "IP://" requests</remarks>
		public IPWebRequest(
			Uri Url)
		{
			// Check the scheme for the Uri is as expected
			if(Url.Scheme.ToLower() != "ip")  // This class is only for ip-style urls
				throw new NotSupportedException("This protocol [" + Url.Scheme + "] is not supported");
			
			// Set data members
			m_RequestUri = Url;
			m_szMethod = string.Empty;  // No default for this class
		}


		// For IP type transports, the socket to listen on is irrelevant as we are blocking on a socket request
		protected override void SetResponseUriFromRequestUri(Uri requestUri)
		{
			throw new NotSupportedException("This protocol [ip] does not support a Response Uri.");
		}


		/// <summary>WSAltTransports.IPWebRequest.GetResponse</summary>
		/// <author>SGregory</author>
		/// <date>16 January 2003</date>
		/// <remarks>
		/// Does the work of placing the serialised Soap message on the named outbound socket call
		/// and waiting for a response.
		/// NOTES:
		/// 1) The URI for the IP endpoints look like:
		///			ip://100.100.100.100:4567
		/// </remarks>
		/// <returns type="System.Net.WebResponse">Our own special brand of WebResponse</returns>
		public override WebResponse GetResponse() 
		{
			IPWebResponse objIPWebResponse = null;
			string strHostIPAddr = string.Empty;
			int intHostPort = 0;
			NetworkStream networkStream = null;

			try
			{
				// Check we don't support a return URI
				if (this.ResponseUri != null &&
					this.ResponseUri.AbsoluteUri.ToString().Trim().Length > 0)
					throw new NotSupportedException("This protocol [ip] does not support a Response Uri.");

				// Access the Soap serialised stream as an array of bytes
				byte[] bytBody = new Byte[m_RequestStream.Length];
				m_RequestStream.Read(bytBody, 0, bytBody.Length);
				m_RequestStream.InternalClose();

				// Fish out HostName information
				strHostIPAddr = this.m_RequestUri.Host;
				intHostPort = this.m_RequestUri.Port;

				// Create a TcpClient
				TcpClient objTcpClient = new TcpClient();

				// Set up the receive timeout on the socket - once breached, a SocketException
				// would be thrown
				objTcpClient.ReceiveTimeout = m_intTimeout;

				// Also, set the outbound buffer size
				objTcpClient.SendBufferSize = bytBody.Length;

				// Connect to the host and port
				try
				{
					objTcpClient.Connect(
						strHostIPAddr, 
						intHostPort);

					// Get a Network stream
					networkStream = objTcpClient.GetStream();

					if (!networkStream.CanRead)
						throw new ApplicationException("You may not write data to this open stream.");
			        else
					if (!networkStream.CanWrite)
						throw new ApplicationException("You may not read data from this open stream.");
				}
				catch(Exception e)
				{
					throw new WebException(
						"Failed to connect to Socket '" + strHostIPAddr + ":" + intHostPort.ToString() + "' when trying to send request.",
						e,
						WebExceptionStatus.ConnectFailure,
						null);
				}

				try
				{
					// Send the message over the Network stream
					networkStream.Write(
						bytBody, 
						0, 
						bytBody.Length);
				}
				catch(Exception e)
				{
					// Throw the exception as a general send failure
					throw new WebException(
						"Failed to send the message over the IP Socket.", 
						e,
						WebExceptionStatus.SendFailure,
						null);
				}
				finally
				{
					// Free resources on main Queue
					objTcpClient.Close();
					
					// And close serialised Soap Stream....
					m_RequestStream.InternalClose();
				}

				// Read the socket response if we can...
				byte[] bytResponseBody = new byte[objTcpClient.ReceiveBufferSize];

				try
				{
					// Reads the NetworkStream into a byte buffer. Default is 8192 bytes.
					networkStream.Read(bytResponseBody, 0, (int) objTcpClient.ReceiveBufferSize);
				}
				catch(Exception e)
				{
					// This handler handles exceptions from the receive process that are non-retryable
					// These include timeouts waiting on the message, and all other exceptions.
					if (e.InnerException != null &&
						e.InnerException.GetType() == typeof(System.Net.Sockets.SocketException))
					{
						if (((SocketException)e.InnerException).ErrorCode == 10060) // WSAETIMEDOUT
							// Throw the exception as a Timeout
							throw new WebException(
								"Timeout waiting on IP Socket resource.", 
								e.InnerException,
								WebExceptionStatus.Timeout,
								null);
						else
							// Just throw it up the way as a Receive failure
							throw new WebException(
								"Failed to receive the message from the IP Socket.", 
								e.InnerException,
								WebExceptionStatus.ReceiveFailure,
								null);
					}
					else
					if ((e is System.Net.WebException) == false)
					{
						// Just throw it up the way as a Receive failure
						throw new WebException(
							"Failed to receive the message from the IP Socket.", 
							e,
							WebExceptionStatus.ReceiveFailure,
							null);
					}
				}
				finally
				{
					// Free resources on main Queue
					objTcpClient.Close();
				}
				
				// If we get here all is well.
				// Convert the result into a byte array
				MemoryStream stResponse = new MemoryStream();
				stResponse.Write(bytResponseBody, 0, bytResponseBody.Length);

				// Create a return, and stream results into it...
				objIPWebResponse = new IPWebResponse();
				objIPWebResponse.SetDownloadStream(stResponse);
			}
			catch(Exception e)
			{
				// All exceptions caught here that are not of the WebException variety
				// get cast as ProtocolErrors - these are exceptions that we do not have
				// a mapping to a standard WebException status type.

				// Close serialised Soap Stream....if it needs closing
				m_RequestStream.InternalClose();

				// Have we already processed this exception in some way?
				if ((e is System.Net.WebException) == false)
				{
					// No - Create a IPWebResponse - this is a protocol specific error
					objIPWebResponse = new IPWebResponse(
						(int)QueueTransportErrors.UnexpectedFailure, 
						e.Message, 
						e.StackTrace);

					// And throw the exception
					throw new WebException(
						"IP Sockets Pluggable Protocol failure.", 
						e,
						WebExceptionStatus.ProtocolError,
						objIPWebResponse);
				}
				else
				{
					// It's prepared already from a lower level, so just
					// throw it on up the chain
					throw e;
				}
			}

			// If we get here we are in business, so return a response
			return objIPWebResponse;
		}	
	}


	/// <summary>WSAltTransports.IPWebResponse</summary>
	/// <author>SGregory</author>
	/// <date>16 January 2003</date>
	/// <remarks>
	/// The IP Response - we totally derive from MyBaseWebResponse here
	/// </remarks>
	public sealed class IPWebResponse : MyBaseWebResponse
	{
		/// <summary>WSAltTransports.IPWebResponse.IPWebResponse</summary>
		/// <author>Simon G</author>
		/// <date>24 February 2003</date>
		/// <remarks>Default constructor - used simply to set up the base class member data</remarks>
		internal IPWebResponse()
		{
		}


		/// <summary>WSAltTransports.IPWebResponse.IPWebResponse</summary>
		/// <author>Simon G</author>
		/// <date>24 February 2003</date>
		/// <remarks>Error information constructor</remarks>
		/// <param name="vintStatusCode" type="int">WebResponse Code e.g. 500</param>
		/// <param name="vstrStatusDescription" type="string">WebResponse Error description</param>
		/// <param name="vstrLog" type="string">Associated stack trace or similar</param>
		/// <postconditions>Error information set up</postconditions>
		internal IPWebResponse(
			int vintStatusCode, 
			string vstrStatusDescription, 
			string vstrLog) 
		{
			// Delegate to the base class for the setting up of the 
			// error information.  This is explicitly shown here through
			// the use of "base."
			base.SetErrorInformation(
				vintStatusCode, 
				vstrStatusDescription, 
				vstrLog);
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Simon Gregory
Web Developer
United Kingdom United Kingdom
I am the Technical Director for Myphones.com, which specialises in developing integrated VoIP products and services for the consumer and SME markets. Technology-wise, we are heavily into the 2nd generation WS stack atop .NET, and basically most things Microsoft, as well as C++ on Linux.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 31 May 2003
Article Copyright 2003 by Simon Gregory
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid