* SoapPort.cs: Implemented.
* MessagingConfiguration.cs: Inital implementation, missing
Load ()
* SoapTransport.cs: Implemented.
* SoapChannelCollection.cs: Implemented.
* SoapChannel.cs: Implemented.
* SoapPlainFormatter.cs: Implemented.
* SoapTcpChannel.cs: Implemented.
* SoapTcpListener.cs: Implemented.
* SoapTcpTransport.cs: Implemented.
* SoapReceiver.cs: Initial implementation.
* SoapReceivers.cs: Initial implementation.
* SoapSender.cs: Initial implementation.
* SoapDimeFormatter.cs: basic stubs.
* ChangeLog: Added.
svn path=/trunk/mcs/; revision=19306
--- /dev/null
+2003-10-22 Todd Berman <tberman@gentoo.org>
+
+ * SoapPort.cs: Implemented.
+ * MessagingConfiguration.cs: Inital implementation, missing Load ()
+ * SoapTransport.cs: Implemented.
+ * SoapChannelCollection.cs: Implemented.
+ * SoapChannel.cs: Implemented.
+ * SoapPlainFormatter.cs: Implemented.
+ * SoapTcpChannel.cs: Implemented.
+ * SoapTcpListener.cs: Implemented.
+ * SoapTcpTransport.cs: Implemented.
+ * SoapReceiver.cs: Initial implementation.
+ * SoapReceivers.cs: Initial implementation.
+ * SoapSender.cs: Initial implementation.
+ * SoapDimeFormatter.cs: basic stubs.
+ * ChangeLog: Added.
\r
int IdleTimeout { get; set; }\r
\r
- string Scheme { get; }\r
+ //string Scheme { get; }\r
\r
IAsyncResult BeginSend ( \r
SoapEnvelope envelope,\r
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.Configuration.MessagingConfiguration.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Xml;
+using System.Collections;
+using Microsoft.Web.Services.Messaging;
+using Microsoft.Web.Services.Configuration;
+
+namespace Microsoft.Web.Services.Messaging.Configuration
+{
+ public class MessagingConfiguration : ConfigurationBase
+ {
+
+ private static Hashtable _transports;
+
+ static MessagingConfiguration ()
+ {
+ _transports = new Hashtable ();
+ }
+
+ public MessagingConfiguration () : base ()
+ {
+ //Add transports here
+ AddTransport ("soap.tcp", new SoapTcpTransport ());
+ }
+
+ public void AddTransport (string scheme, ISoapTransport trans)
+ {
+ if(scheme == null || scheme.Length == 0) {
+ throw new ArgumentNullException ("scheme");
+ }
+ if(trans == null) {
+ throw new ArgumentNullException ("transport");
+ }
+ _transports[scheme] = trans;
+ }
+
+ public ISoapTransport GetTransport (string scheme)
+ {
+ if(scheme == null || scheme.Length == 0) {
+ throw new ArgumentNullException ("scheme");
+ }
+ return (ISoapTransport)_transports[scheme];
+ }
+
+ public void RemoveTransport (string scheme)
+ {
+ if(scheme == null || scheme.Length == 0) {
+ throw new ArgumentNullException ("scheme");
+ }
+ _transports.Remove (scheme);
+ }
+
+ [MonoTODO]
+ public void Load (XmlNode node)
+ {
+ throw new NotImplementedException ();
+ }
+
+ public ICollection Transports {
+ get { return _transports.Values; }
+ }
+
+ }
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapChannel.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.IO;
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public abstract class SoapChannel
+ {
+
+ private ISoapFormatter _formatter;
+ private object _sync_obj = new object ();
+
+ public SoapChannel (ISoapFormatter format)
+ {
+ if(format == null) {
+ throw new ArgumentNullException ("formatter");
+ }
+ _formatter = format;
+ }
+
+ public abstract void Close ();
+
+ public SoapEnvelope DeserializeMessage (Stream stream)
+ {
+ return _formatter.Deserialize (stream);
+ }
+
+ public void SerializeMessage (SoapEnvelope envelope, Stream stream)
+ {
+ _formatter.Serialize (envelope, stream);
+ }
+
+ public abstract SoapEnvelope Receive ();
+ public abstract void Send (SoapEnvelope envelope);
+
+ public abstract bool Active {
+ get;
+ }
+
+ public abstract string Scheme {
+ get;
+ }
+
+ public object SyncRoot {
+ get { return _sync_obj; }
+ }
+
+ public IAsyncResult BeginReceive (AsyncCallback callback, object state)
+ {
+ return new ReceiveAsyncResult (this, callback, state);
+ }
+
+ public SoapEnvelope EndReceive (IAsyncResult result)
+ {
+ if(result == null) {
+ throw new ArgumentNullException ("result");
+ }
+
+ ReceiveAsyncResult res = result as ReceiveAsyncResult;
+
+ if(res != null) {
+ ReceiveAsyncResult.End (result);
+ return res.Envelope;
+ }
+
+ throw new InvalidOperationException ("Invalid IAsyncResult type");
+ }
+
+ public IAsyncResult BeginSend (SoapEnvelope env, AsyncCallback callback, object state)
+ {
+ if(env == null) {
+ throw new ArgumentNullException ("envelope");
+ }
+ return new SendAsyncResult (this, env, callback, state);
+ }
+
+ public void EndSend (IAsyncResult result)
+ {
+ if(result == null) {
+ throw new ArgumentNullException ("result");
+ }
+ SendAsyncResult a_res = result as SendAsyncResult;
+
+ if(a_res != null) {
+ AsyncResult.End (result);
+ }
+ throw new InvalidOperationException ("Invalid IAsyncResult type");
+ }
+
+ protected class ReceiveAsyncResult : AsyncResult
+ {
+ private SoapEnvelope _envelope;
+
+ private delegate SoapEnvelope Receive ();
+
+ public ReceiveAsyncResult (SoapChannel channel,
+ AsyncCallback callback,
+ object state) : base (callback, state)
+ {
+ Receive rec = new Receive (channel.Receive);
+
+ rec.BeginInvoke (new AsyncCallback (OnReceiveComplete), rec);
+ }
+
+ private void OnReceiveComplete (IAsyncResult result)
+ {
+ Receive rec = (Receive) result.AsyncState;
+
+ try {
+ _envelope = rec.EndInvoke (result);
+ Complete (result.CompletedSynchronously);
+ } catch (Exception e) {
+ Complete (result.CompletedSynchronously, e);
+ }
+ }
+
+ public SoapEnvelope Envelope {
+ get { return _envelope; }
+ }
+ }
+
+ protected class SendAsyncResult : AsyncResult
+ {
+ private delegate void Send (SoapEnvelope e);
+
+ public SendAsyncResult (SoapChannel channel,
+ SoapEnvelope env,
+ AsyncCallback callback,
+ object state) : base (callback, state)
+ {
+ Send send_delegate = new Send (channel.Send);
+ send_delegate.BeginInvoke (env, new AsyncCallback (OnSendComplete), send_delegate);
+ }
+
+ private void OnSendComplete (IAsyncResult result)
+ {
+ Send s_del = result.AsyncState as Send;
+
+ try {
+ s_del.EndInvoke (result);
+ this.Complete (result.CompletedSynchronously);
+ } catch (Exception e) {
+ Complete (result.CompletedSynchronously, e);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapChannelCollection.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Collections;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public class SoapChannelCollection
+ {
+
+ private Hashtable _channels = new Hashtable ();
+
+ public void Add (string to, SoapChannel channel)
+ {
+ if(to == null || to.Length == 0) {
+ throw new ArgumentNullException ("to");
+ }
+ if(channel == null) {
+ throw new ArgumentNullException ("channel");
+ }
+
+ _channels[to] = channel;
+ }
+
+ public void Clear ()
+ {
+ _channels.Clear ();
+ }
+
+ public bool Contains (string to)
+ {
+ if(to == null || to.Length == 0) {
+ throw new ArgumentNullException ("to");
+ }
+ return _channels.Contains (to);
+ }
+
+ public IEnumerator GetEnumerator ()
+ {
+ return _channels.Values.GetEnumerator ();
+ }
+
+ public void Remove (string to)
+ {
+ if(to == null || to.Length == 0) {
+ throw new ArgumentNullException ("to");
+ }
+ _channels.Remove (to);
+ }
+
+ public int Count {
+ get { return _channels.Values.Count; }
+ }
+
+ public SoapChannel this [string index] {
+ get { return (SoapChannel) _channels[index]; }
+ }
+
+ public ICollection Keys {
+ get { return _channels.Keys; }
+ }
+
+ public object SyncRoot {
+ get { return _channels.SyncRoot; }
+ }
+
+ public ICollection Values {
+ get { return _channels.Values; }
+ }
+ }
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapDimeFormatter.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.IO;
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public class SoapDimeFormatter : ISoapFormatter
+ {
+
+ [MonoTODO]
+ public SoapEnvelope Deserialize (Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public void Serialize (SoapEnvelope envelope, Stream stream)
+ {
+ throw new NotImplementedException ();
+ }
+ }
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapPlainFormatter.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.IO;
+
+//FIXME: Can be removed when workaround is removed.
+using System.Text;
+using System.Net.Sockets;
+
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public class SoapPlainFormatter : ISoapFormatter
+ {
+ public SoapEnvelope Deserialize (Stream stream)
+ {
+ if(stream == null) {
+ throw new ArgumentNullException ("stream");
+ }
+ SoapEnvelope env = new SoapEnvelope ();
+ //env.Load (stream);
+
+
+ //FIXME: Workaround for XmlDocument.Load's love of stream closing
+ byte[] buf = new byte[1024];
+ String msg = "";
+ int numRead = 0;
+
+ do {
+ numRead = stream.Read(buf, 0, buf.Length);
+ msg = String.Concat (msg, Encoding.ASCII.GetString (buf, 0, numRead));
+ } while(((NetworkStream)stream).DataAvailable);
+
+ env.LoadXml (msg);
+
+ return env;
+ }
+
+ [MonoTODO("Should error if envelope has DimeAttachments")]
+ public void Serialize (SoapEnvelope env, Stream stream)
+ {
+ if(stream == null) {
+ throw new ArgumentNullException ("stream");
+ }
+ if(env == null) {
+ throw new ArgumentNullException ("envelope");
+ }
+
+ env.Save (stream);
+ stream.Flush();
+ }
+ }
+}
-namespace Microsoft.Web.Services.Messaging {
+//
+// Microsoft.Web.Services.Messaging.SoapPort.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using Microsoft.Web.Services;
+
+namespace Microsoft.Web.Services.Messaging
+{
public abstract class SoapPort
{
+ private Pipeline _pipeline;
+
+ public SoapPort () : base ()
+ {
+ _pipeline = null;
+ }
+
+ protected abstract void FilterMessage (SoapEnvelope env);
+
+ public Pipeline Pipeline {
+ get {
+ if(_pipeline == null) {
+ _pipeline = new Pipeline ();
+ }
+ return _pipeline;
+ }
+ set { _pipeline = value; }
+ }
}
}
+//
+// Microsoft.Web.Services.Messaging.SoapReceiver.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
using System;
using System.Web;
using Microsoft.Web.Services;
+using Microsoft.Web.Services.Addressing;
+using Microsoft.Web.Services.Configuration;
namespace Microsoft.Web.Services.Messaging {
public abstract class SoapReceiver : SoapPort, IHttpHandler
{
+ private static Pipeline _defPipe = new Pipeline ();
+
protected abstract void Receive (SoapEnvelope envelope);
- [MonoTODO]
- public bool IsReusable {
+ public SoapReceiver () : base ()
+ {
+ }
+
+ protected void Receive (SoapEnvelope envelope, Exception e)
+ {
+ }
+
+ public static void DispatchMessage (SoapEnvelope env)
+ {
+ DispatchMessage (env, null);
+ }
+
+ public static void DispatchMessage (SoapEnvelope env, RelatesTo relation)
+ {
+ if(env == null) {
+ throw new ArgumentNullException ("envelope");
+ }
+ SoapReceiver rec = null;
+ AddressingHeaders header = null;
+
+ try {
+
+ header = env.Context.Addressing;
+
+ header.Load (env);
+
+ if(header.RelatesTo != null || header.To != null || relation != null)
+ {
+ object to = null;
+ if(header.RelatesTo != null) {
+ if(WebServicesConfiguration.MessagingConfiguration.GetTransport (header.RelatesTo.Value.Scheme) == null) {
+ //FIXME: Incorrect exception here, should be using something in Routing.
+ throw new ArgumentException ("Transport " + header.RelatesTo.Value.Scheme + " is not supported");
+ }
+ to = SoapReceivers.Receiver (header.RelatesTo.Value);
+ env.Context.SetActor (header.RelatesTo);
+ }
+ if(to == null && header.To != null) {
+ if(env.Context.Channel.Scheme != header.To.Value.Scheme) {
+ //FIXME: Incorrect exception again.
+ throw new ArgumentException ("Channel's Scheme and To's Scheme are not the same.");
+ }
+ to = SoapReceivers.Receiver (header.To.Value);
+ env.Context.SetActor (header.RelatesTo);
+ }
+ if(to == null && relation != null) {
+ to = SoapReceivers.Receiver (relation.Value);
+ env.Context.Addressing.RelatesTo = relation;
+ env.Context.SetActor (relation);
+ }
+ if(to != null) {
+ rec = to as SoapReceiver;
+ if(rec == null) {
+ rec = (SoapReceiver) Activator.CreateInstance (to as Type);
+ }
+ if(rec != null) {
+ Exception excep = null;
+ try {
+ env.Context.SetIsInbound (true);
+ rec.FilterMessage (env);
+ } catch (Exception e) {
+ excep = e;
+ }
+ if(excep != null) {
+ //FIXME: again, wrong exception type, should be throwing something XmlElement like
+ rec.Receive (env, excep);
+ } else {
+ rec.Receive (env);
+ }
+ } else {
+ //FIXME: same thing
+ throw new InvalidOperationException ("no receiver found");
+ }
+ } else {
+ //FIXME: same
+ throw new InvalidOperationException ("no receiver found pt 2");
+ }
+ }
+ } catch (Exception e) {
+ if(rec == null) {
+ DispatchMessageFault (env, e);
+ } else {
+ DispatchMessageFault (env, e, rec.Pipeline);
+ }
+ }
+ }
+
+ public static void DispatchMessageFault (SoapEnvelope env, Exception e)
+ {
+ DispatchMessageFault (env, e, _defPipe);
+ }
+
+ public static void DispatchMessageFault (SoapEnvelope env, Exception e, Pipeline pipe)
+ {
+ }
+
+ public bool IsReusable {
get {
- throw new NotImplementedException ();
- }
+ return true;
+ }
}
- [MonoTODO]
+ protected override void FilterMessage (SoapEnvelope env)
+ {
+ if(env == null) {
+ throw new ArgumentNullException ("envelope");
+ }
+ Pipeline.ProcessInputMessage (env);
+ }
+
+ public void ProcessSoapRequest (HttpContext context)
+ {
+
+ }
+
+ public void ProcessNonSoapRequest (HttpContext context)
+ {
+
+ }
+
public void ProcessRequest (HttpContext context)
{
- throw new NotImplementedException ();
- }
+ if(context.Request.HttpMethod == "POST" || context.Request.Headers["SOAPAction"] != null) {
+ ProcessSoapRequest (context);
+ }
+ ProcessNonSoapRequest (context);
+ }
}
}
// (C) 2003 Todd Berman
using System;
+using System.Collections;
+using Microsoft.Web.Services.Configuration;
namespace Microsoft.Web.Services.Messaging
{
public class SoapReceivers
{
- [MonoTODO]
+ private static Hashtable _receivers = new Hashtable ();
+
+ private SoapReceivers () { }
+
public static void Add (Uri uri, SoapReceiver receiver)
{
- throw new NotImplementedException ();
+ Add (uri, receiver, false);
+ }
+
+ public static void Add (Uri uri, Type type)
+ {
+ Add (uri, type, false);
+ }
+
+ public static void Add (Uri uri, SoapReceiver receiver, bool passive)
+ {
+ if(uri == null) {
+ throw new ArgumentNullException ("uri");
+ }
+ if(receiver == null) {
+ throw new ArgumentNullException ("receiver");
+ }
+
+ lock(SyncRoot) {
+ if(_receivers.Contains (uri)) {
+ throw new ArgumentException ("An item with this key already exists");
+ }
+
+ if(passive == false) {
+ ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (uri.Scheme);
+
+ if(trans != null) {
+ trans.RegisterPort (uri, receiver);
+ } else {
+ throw new NotSupportedException ("Transport " + uri.Scheme + " not supported.");
+ }
+ }
+
+ _receivers.Add (uri, receiver);
+ }
+ }
+
+ public static void Add (Uri uri, Type type, bool passive)
+ {
+ if(uri == null) {
+ throw new ArgumentNullException ("uri");
+ }
+ if(type == null) {
+ throw new ArgumentNullException ("type");
+ }
+ lock(SyncRoot) {
+ if(_receivers.Contains (uri)) {
+ throw new ArgumentException ("An item with this key already exists");
+ }
+
+ if(passive == false) {
+ ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (uri.Scheme);
+
+ if(trans != null) {
+ trans.RegisterPort (uri, type);
+ } else {
+ throw new NotSupportedException ("Transport " + uri.Scheme + " is not supported");
+ }
+ }
+
+ _receivers.Add (uri, type);
+ }
+ }
+
+ public static void Clear ()
+ {
+ lock(SyncRoot) {
+ foreach(ISoapTransport trans in WebServicesConfiguration.MessagingConfiguration.Transports) {
+ trans.UnregisterAll ();
+ }
+ _receivers.Clear ();
+ }
+ }
+
+ public static bool Contains (Uri to)
+ {
+ if(to == null) {
+ throw new ArgumentNullException ("to");
+ }
+ bool retVal = false;
+ lock(SyncRoot) {
+ retVal = _receivers.Contains (to);
+ }
+ return retVal;
+ }
+
+ public static IDictionaryEnumerator GetEnumerator ()
+ {
+ return _receivers.GetEnumerator ();
+ }
+
+ public static object Receiver (Uri to)
+ {
+ return _receivers[to];
}
- [MonoTODO]
public static void Remove (Uri to)
{
- throw new NotImplementedException ();
+ if(to == null) {
+ throw new ArgumentNullException ("to");
+ }
+
+ lock(SyncRoot) {
+ if(_receivers.Contains (to) == false) {
+ ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (to.Scheme);
+ if(trans != null) {
+ trans.UnregisterPort (to);
+ _receivers.Remove (to);
+ }
+ }
+ }
}
- }
+ public static int Count {
+ get { return _receivers.Values.Count; }
+ }
+ public static object SyncRoot {
+ get { return _receivers.SyncRoot; }
+ }
+ }
}
using System.Web;
using Microsoft.Web.Services;
using Microsoft.Web.Services.Addressing;
+using Microsoft.Web.Services.Configuration;
namespace Microsoft.Web.Services.Messaging {
public class SoapSender : SoapPort
{
- [MonoTODO]
- public SoapSender ()
+ private EndpointReference _destination = null;
+ private ISoapTransport _transport = null;
+
+ public SoapSender () : base ()
{
- throw new NotImplementedException ();
}
- [MonoTODO]
- public SoapSender (EndpointReference destination)
+ public SoapSender (EndpointReference dest) : base ()
{
- throw new NotImplementedException ();
+ if(dest == null) {
+ throw new ArgumentNullException ("destination");
+ }
+ Destination = dest;
+ }
+
+ public SoapSender (Uri destination) : this (new EndpointReference (destination))
+ {
+ }
+
+ protected override void FilterMessage (SoapEnvelope env)
+ {
+ if(env == null) {
+ throw new ArgumentNullException ("envelope");
+ }
+ Pipeline.ProcessOutputMessage (env);
+ }
+
+ public void Send (SoapEnvelope env)
+ {
+ if(env == null) {
+ throw new ArgumentNullException ("envelope");
+ }
+ if(env.Context.Action == null) {
+ throw new ArgumentException ("Action not set");
+ }
+ if(env.Processed == true || env.Context.Processed == true) {
+ throw new ArgumentException ("Attempting to re-process an envelope");
+ }
+
+ if(_destination == null) {
+ throw new ArgumentException ("Destination is not set, cant send");
+ }
+ if(_transport == null) {
+ throw new ArgumentException ("Transport is not set, cant send");
+ }
+
+ env.Context.SetTo(_destination.Address);
+
+ FilterMessage (env);
+
+ _transport.Send (env, _destination);
}
[MonoTODO]
- public SoapSender (Uri destination)
+ public IAsyncResult BeginSend (SoapEnvelope env, AsyncCallback callback, object state)
{
throw new NotImplementedException ();
- }
+ }
[MonoTODO]
- public void Send (SoapEnvelope env)
+ public void EndSend (IAsyncResult result)
{
throw new NotImplementedException ();
}
-
+
+ public ISoapTransport Transport {
+ get { return _transport; }
+ }
+
+ public EndpointReference Destination {
+ get { return _destination; }
+ set {
+ if(value == null || value.Address == null || value.Address.Value == null) {
+ throw new ArgumentNullException ("destination");
+ }
+ ISoapTransport trans = WebServicesConfiguration.MessagingConfiguration.GetTransport (value.Address.Value.Scheme);
+ if(trans == null) {
+ throw new ArgumentException ("Transport " + value.Address.Value.Scheme + " is not supported");
+ }
+ _destination = value;
+ _transport = trans;
+ }
+ }
}
}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapTcpChannel.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Microsoft.Web.Services.Messaging
+{
+
+ public class SoapTcpChannel : SoapChannel
+ {
+
+ private bool _active = false;
+ private bool _disposed = false;
+ private AddressFamily _addrFam = AddressFamily.InterNetwork;
+ private DateTime _lastActivity = DateTime.Now;
+ private int _port = 0;
+ private Socket _socket = null;
+ private NetworkStream _stream = null;
+ private Uri _destination = null;
+ private string _hostname = null;
+
+ public SoapTcpChannel (Socket sock, ISoapFormatter format) : base (format)
+ {
+ _socket = sock;
+ _stream = new NetworkStream (sock, false);
+ _active = true;
+
+ IPEndPoint ep = sock.RemoteEndPoint as IPEndPoint;
+
+ _destination = new Uri ("soap.tcp://" + ep.Address.ToString () + ":" + ep.Port);
+ }
+
+ public SoapTcpChannel (Uri uri, ISoapFormatter format) : base (format)
+ {
+ if(uri == null) {
+ throw new ArgumentNullException ("to");
+ }
+ if(uri.Scheme != "soap.tcp") {
+ throw new ArgumentException ("Invalid Scheme");
+ }
+ _hostname = uri.Host;
+ _port = uri.Port < 0 ? 8081 : uri.Port;
+ }
+
+ public new void Close ()
+ {
+ lock(SyncRoot) {
+ try {
+ _active = false;
+ if(_socket != null || !_socket.Connected) {
+ _socket.Close ();
+ }
+ } catch {
+ _socket = null;
+ }
+ }
+ }
+
+ public void Connect ()
+ {
+ if(_disposed) {
+ throw new ObjectDisposedException (GetType ().FullName);
+ }
+ if(_active) {
+ return;
+ }
+ lock(SyncRoot) {
+ if(_active) {
+ return;
+ }
+ IPHostEntry host = Dns.Resolve (_hostname);
+
+ IPAddress[] ip_addrs = host.AddressList;
+
+ Exception exception = null;
+
+ for (int i = 0; i < ip_addrs.Length; i++) {
+ IPAddress addy = ip_addrs[i];
+
+ _addrFam = addy.AddressFamily;
+ _socket = new Socket (_addrFam, SocketType.Stream, ProtocolType.Tcp);
+ _active = false;
+
+ try {
+ Connect ( new IPEndPoint (addy, _port) );
+ break;
+ } catch (Exception e) {
+ _socket.Close ();
+ _socket = null;
+ exception = e;
+ }
+ }
+
+ if(_active == false) {
+ if(exception != null) {
+ throw exception;
+ }
+
+ throw new Exception ("Not Connected");
+ }
+ _stream = new NetworkStream (_socket, false);
+ }
+ }
+
+ public void Connect (IPEndPoint endpoint)
+ {
+ if(_disposed) {
+ throw new ObjectDisposedException (GetType ().FullName);
+ }
+ if(endpoint == null) {
+ throw new ArgumentNullException ("endpoint");
+ }
+
+ _socket.Connect (endpoint);
+ _active = true;
+ UpdateLastActivity ();
+ }
+
+
+ ~SoapTcpChannel ()
+ {
+ if(_active == false) {
+ Close ();
+ _disposed = true;
+ }
+ }
+
+
+ public new SoapEnvelope Receive ()
+ {
+ if(!_active) {
+ Connect ();
+ }
+
+ SoapEnvelope env = DeserializeMessage (_stream);
+
+ if(env != null) {
+ env.Context.Channel = this;
+ }
+
+ UpdateLastActivity ();
+
+ return env;
+ }
+
+ public new void Send (SoapEnvelope env)
+ {
+ lock(SyncRoot) {
+ if(!_active) {
+ Connect ();
+ }
+ SerializeMessage (env, _stream);
+ UpdateLastActivity ();
+ }
+ }
+
+ public void UpdateLastActivity ()
+ {
+ lock (SyncRoot) {
+ _lastActivity = DateTime.Now;
+ }
+ }
+
+ public new bool Active {
+ get { return _active; }
+ }
+
+ public Uri Destination {
+ get { return _destination; }
+ }
+
+ public DateTime LastActivity {
+ get { return _lastActivity; }
+ }
+
+ public new string Scheme {
+ get { return "soap.tcp"; }
+ }
+
+ }
+
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapTcpListener.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public class SoapTcpListener : TcpListener
+ {
+
+ private int _refs = 0;
+
+ private delegate Socket AcceptSocket ();
+
+ private AcceptSocket _acceptSocket;
+
+ public SoapTcpListener (IPEndPoint endpoint) : base (endpoint)
+ {
+ if(Server == null) {
+ Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+ }
+ }
+
+ public SoapTcpListener (IPAddress address, int port) : base (address, port)
+ {
+ if(Server == null) {
+ Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+ }
+ }
+
+ public SoapTcpListener (int port) : base (port)
+ {
+ if(Server == null) {
+ Server.SetSocketOption (SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
+ }
+ }
+
+ public void AddReference ()
+ {
+ _refs++;
+ }
+
+ public int ReleaseReference ()
+ {
+ return --_refs;
+ }
+
+ public IAsyncResult BeginAcceptSocket (AsyncCallback callback, object state)
+ {
+ if(_acceptSocket == null) {
+ _acceptSocket = new AcceptSocket (base.AcceptSocket);
+ }
+ return _acceptSocket.BeginInvoke (callback, state);
+ }
+
+ public Socket EndAcceptSocket (IAsyncResult result)
+ {
+ return _acceptSocket.EndInvoke (result);
+ }
+
+ public bool IsListening {
+ get { return Active; }
+ }
+ }
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapTcpTransport.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Collections;
+using Microsoft.Web.Services;
+using Microsoft.Web.Services.Addressing;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public class SoapTcpTransport : SoapTransport, ISoapTransport
+ {
+
+ public static string Scheme = "soap.tcp";
+
+ private Hashtable _listeners = new Hashtable ();
+ private Hashtable _receivers = new Hashtable ();
+
+ public SoapTcpChannel GetTcpChannel (Uri to)
+ {
+ SoapTcpChannel chan = null;
+ lock (Channels.SyncRoot) {
+ int port = (to.Port == -1) ? 8081 : to.Port;
+
+ Uri uri = new Uri (String.Format("{0}://{1}:{2}", Scheme, to.Host, port));
+
+ chan = Channels[uri.AbsoluteUri] as SoapTcpChannel;
+
+ if(chan == null) {
+ SoapTcpChannel newChan = new SoapTcpChannel (uri, Formatter);
+ Channels.Add (uri.AbsoluteUri, newChan);
+
+ newChan.BeginReceive(new AsyncCallback (OnReceive), newChan);
+ chan = newChan;
+
+ }
+ }
+ return chan;
+ }
+
+ public IAsyncResult BeginSend (SoapEnvelope env,
+ Uri dest,
+ AsyncCallback callback,
+ object state)
+ {
+ SoapTcpChannel chan = GetTcpChannel (dest);
+
+ return new SendAsyncResult (chan, env, callback, state);
+ }
+
+ public void EndSend (IAsyncResult result)
+ {
+ if(result == null) {
+ throw new ArgumentNullException ("result");
+ }
+
+ if(result is SendAsyncResult) {
+ AsyncResult.End (result);
+ } else {
+ throw new InvalidOperationException ("Invalid IAsyncResult Type");
+ }
+ }
+
+ public void RegisterPort (Uri to, Type rType)
+ {
+ GenericRegister (to, rType);
+ }
+
+ public void RegisterPort (Uri to, SoapReceiver rec)
+ {
+ GenericRegister (to, rec);
+ }
+
+ private void GenericRegister (Uri to, object rType)
+ {
+ if(to == null) {
+ throw new ArgumentNullException ("to");
+ }
+ if(Scheme != to.Scheme) {
+ throw new ArgumentException ("invalid Scheme");
+ }
+ //if(to.Host != "localhost") {
+ // throw new ArgumentException ("Host name " + to.Host + " does not equal " + Dns.GetHostName() );
+ //}
+
+ lock(Channels.SyncRoot) {
+ if(Receivers.Contains (to) == true) {
+ throw new ArgumentException ("URI has already been registered");
+ }
+ int port = to.Port <= -1 ? 8081 : to.Port;
+ Uri to_with_port = new Uri (Scheme + "://" + to.Host + ":" + port);
+ SoapTcpListener tcp = (SoapTcpListener) _listeners[to_with_port];
+
+ if(tcp == null) {
+
+ //This is what Hervey says it does, not WSE2 TP tested.
+
+ if(to.Host == "localhost") {
+ tcp = new SoapTcpListener (IPAddress.Loopback, port);
+ } else {
+ tcp = new SoapTcpListener (IPAddress.Any, port);
+ }
+
+ tcp.Start ();
+ tcp.AddReference ();
+
+ tcp.BeginAcceptSocket (new AsyncCallback (OnAcceptSocket), tcp);
+
+ _listeners[to_with_port] = tcp;
+ } else {
+ tcp.AddReference ();
+ }
+
+ Receivers[to] = rType;
+ }
+ }
+
+ public void Send (SoapEnvelope env, Uri to)
+ {
+ SoapTcpChannel tcp = GetTcpChannel (to);
+
+ tcp.Send (env);
+ }
+
+ public void UnregisterAll ()
+ {
+ lock (Channels.SyncRoot) {
+
+ Receivers.Clear ();
+ foreach(SoapTcpListener tcp in _listeners.Values) {
+ tcp.Stop ();
+ }
+ _listeners.Clear ();
+ }
+ }
+
+ public void UnregisterPort (Uri to)
+ {
+ if(to == null) {
+ throw new ArgumentNullException ("to");
+ }
+ lock(Channels.SyncRoot) {
+ int port = to.Port < 0 ? 8081 : to.Port;
+
+ Uri newTo = new Uri (Scheme + "://" + to.Host + ":" + port);
+ SoapTcpListener tcp = _listeners[newTo] as SoapTcpListener;
+
+ if(tcp != null) {
+ if(tcp.ReleaseReference () == 0) {
+ _listeners.Remove(newTo);
+ tcp.Stop();
+ }
+ Receivers.Remove(to);
+ }
+ }
+ }
+
+ //private string Scheme {
+ // get { return "soap.tcp"; }
+ //}
+
+ private void OnAcceptSocket (IAsyncResult result)
+ {
+ try {
+ SoapTcpListener tcp = (SoapTcpListener) result.AsyncState;
+
+ if(tcp != null) {
+ Socket sock = tcp.EndAcceptSocket (result);
+ if(tcp.IsListening != true) {
+ tcp.BeginAcceptSocket (new AsyncCallback (OnAcceptSocket), result);
+ }
+ if(sock != null) {
+ SoapTcpChannel chan = new SoapTcpChannel (sock, Formatter);
+ lock (Channels.SyncRoot) {
+ Channels.Add (chan.Destination.AbsoluteUri, chan);
+ }
+ chan.BeginReceive (new AsyncCallback (OnReceive), chan);
+ }
+ }
+ } catch (Exception)
+ {
+ }
+ }
+
+ private void OnReceive (IAsyncResult result)
+ {
+ SoapTcpChannel tcp = result.AsyncState as SoapTcpChannel;
+ SoapEnvelope env = null;
+
+ try {
+ env = tcp.EndReceive (result);
+ tcp.BeginReceive (new AsyncCallback (OnReceive), result);
+ } catch (Exception e) {
+ lock (Channels.SyncRoot) {
+ Channels.Remove (tcp.Destination.AbsoluteUri);
+ tcp.Close ();
+ }
+ }
+
+ if(env != null) {
+ env.Context.Channel = tcp;
+
+ AddressingHeaders header = env.Context.Addressing;
+
+ header.Load (env);
+
+ //FIXME: There is a lot more checking to do here for a valid message.
+ if(header.To != null) {
+ if(header.To.Value.Scheme != "soap.tcp") {
+ SoapReceiver.DispatchMessageFault (env, new ArgumentException ("soap error"));
+ }
+ }
+ SoapReceiver.DispatchMessage (env);
+ }
+ }
+
+ protected IDictionary Receivers {
+ get { return _receivers; }
+ }
+
+ }
+}
--- /dev/null
+//
+// Microsoft.Web.Services.Messaging.SoapTransport.cs
+//
+// Author: Todd Berman <tberman@gentoo.org>
+//
+// (C) 2003 Todd Berman
+
+using System;
+using System.Net;
+
+namespace Microsoft.Web.Services.Messaging
+{
+ public abstract class SoapTransport
+ {
+ private SoapChannelCollection _channels;
+ private ICredentials _credentials;
+ private ISoapFormatter _formatter;
+ private int _timeout;
+
+ [MonoTODO("DimeFormatter is the default here, but not impl yet")]
+ protected SoapTransport () : base ()
+ {
+ _credentials = null;
+ _formatter = new SoapPlainFormatter ();
+ _channels = new SoapChannelCollection ();
+ _timeout = 120000;
+ }
+
+ public SoapChannelCollection Channels {
+ get { return _channels; }
+ }
+
+ public ICredentials Credentials {
+ get { return _credentials; }
+ set { _credentials = value; }
+ }
+
+ public ISoapFormatter Formatter {
+ get { return _formatter; }
+ set {
+ if(value == null) {
+ throw new ArgumentNullException ("formatter");
+ }
+ _formatter = value;
+ }
+ }
+
+ public int IdleTimeout {
+ get { return _timeout; }
+ set {
+ if(value < 0) {
+ throw new ArgumentNullException ("Timeout");
+ }
+ _timeout = value;
+ }
+ }
+
+ protected class SendAsyncResult : AsyncResult
+ {
+ private delegate void Send (SoapEnvelope env);
+
+ private SoapChannel _channel;
+
+ public SendAsyncResult (SoapChannel chan,
+ SoapEnvelope env,
+ AsyncCallback callback,
+ object state) : base (callback, state)
+ {
+ _channel = chan;
+ chan.BeginSend (env, new AsyncCallback (OnSendComplete), null);
+ }
+
+ public void OnSendComplete (IAsyncResult result)
+ {
+ try {
+ _channel.EndSend (result);
+ Complete (result.CompletedSynchronously);
+ } catch (Exception e) {
+ Complete (result.CompletedSynchronously, e);
+ }
+ }
+
+ public SoapChannel Channel {
+ get { return _channel; }
+ }
+ }
+ }
+}