Browse Source

Implemented basic UDP transport.

Atsushi Eno 15 years ago
parent
commit
9f0b95f19e

+ 0 - 2
mcs/class/System.ServiceModel.Discovery/System.ServiceModel.Discovery.Udp/UdpChannelFactory.cs

@@ -40,12 +40,10 @@ namespace System.ServiceModel.Discovery
 		
 		protected override void OnOpen (TimeSpan timeout)
 		{
-			throw new NotImplementedException ();
 		}
 		
 		protected override void OnClose (TimeSpan timeout)
 		{
-			throw new NotImplementedException ();
 		}
 		
 		Action<TimeSpan> open_delegate, close_delegate;

+ 15 - 4
mcs/class/System.ServiceModel.Discovery/System.ServiceModel.Discovery.Udp/UdpChannelListener.cs

@@ -27,6 +27,7 @@ using System.IO;
 using System.Net.Sockets;
 using System.ServiceModel;
 using System.ServiceModel.Channels;
+using System.Threading;
 
 namespace System.ServiceModel.Discovery
 {
@@ -42,6 +43,8 @@ namespace System.ServiceModel.Discovery
 		}
 		
 		Uri listen_uri;
+		UdpDuplexChannel channel;
+		ManualResetEvent accept_wait_handle = new ManualResetEvent (true);
 		
 		public override Uri Uri {
 			get { return listen_uri; }
@@ -49,17 +52,18 @@ namespace System.ServiceModel.Discovery
 		
 		protected override void OnOpen (TimeSpan timeout)
 		{
-			throw new NotImplementedException ();
 		}
 		
 		protected override void OnClose (TimeSpan timeout)
 		{
-			throw new NotImplementedException ();
+			if (channel != null)
+				channel.Close (timeout);
 		}
 		
 		protected override void OnAbort ()
 		{
-			throw new NotImplementedException ();
+			if (channel != null)
+				channel.Abort ();
 		}
 		
 		Action<TimeSpan> open_delegate, close_delegate;
@@ -90,7 +94,14 @@ namespace System.ServiceModel.Discovery
 
 		protected override IDuplexChannel OnAcceptChannel (TimeSpan timeout)
 		{
-			throw new NotImplementedException ();
+			if (!accept_wait_handle.WaitOne (timeout))
+				throw new TimeoutException ();
+			accept_wait_handle.Reset ();
+			channel = new UdpDuplexChannel (this);
+			channel.Closed += delegate {
+				accept_wait_handle.Set ();
+			};
+			return channel;
 		}
 		
 		protected override bool OnWaitForChannel (TimeSpan timeout)

+ 51 - 6
mcs/class/System.ServiceModel.Discovery/System.ServiceModel.Discovery.Udp/UdpDuplexChannel.cs

@@ -24,6 +24,9 @@
 //
 using System;
 using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
 using System.Net.Sockets;
 using System.ServiceModel;
 using System.ServiceModel.Channels;
@@ -33,24 +36,32 @@ namespace System.ServiceModel.Discovery
 	internal class UdpDuplexChannel : ChannelBase, IDuplexChannel
 	{
 		// channel factory
-		public UdpDuplexChannel (UdpChannelFactory factory, BindingContext ctx, EndpointAddress address, Uri via)
+		public UdpDuplexChannel (UdpChannelFactory factory, BindingContext context, EndpointAddress address, Uri via)
 			: base (factory)
 		{
+			if (factory == null)
+				throw new ArgumentNullException ("factory");
+			if (context == null)
+				throw new ArgumentNullException ("context");
+			if (address == null)
+				throw new ArgumentNullException ("address");
+
 			binding_element = factory.Source;
 			RemoteAddress = address;
 			Via = via;
+			FillMessageEncoder (context);
 		}
 		
-		public UdpDuplexChannel (UdpChannelListener listener, Uri listenUri)
+		public UdpDuplexChannel (UdpChannelListener listener)
 			: base (listener)
 		{
 			binding_element = listener.Source;
-			LocalAddress = new EndpointAddress (listenUri);
+			LocalAddress = new EndpointAddress (listener.Uri);
+			FillMessageEncoder (listener.Context);
 		}
 		
 		MessageEncoder message_encoder; // FIXME: fill it
 		UdpClient client;
-		UdpTransportSettings settings;
 		UdpTransportBindingElement binding_element;
 		
 		// for servers
@@ -59,6 +70,14 @@ namespace System.ServiceModel.Discovery
 		public EndpointAddress RemoteAddress { get; private set; }
 		
 		public Uri Via { get; private set; }
+
+		void FillMessageEncoder (BindingContext ctx)
+		{
+			var mbe = (MessageEncodingBindingElement) ctx.RemainingBindingElements.FirstOrDefault (be => be is MessageEncodingBindingElement);
+			if (mbe == null)
+				mbe = new TextMessageEncodingBindingElement ();
+			message_encoder = mbe.CreateMessageEncoderFactory ().Encoder;
+		}
 		
 		public void Send (Message message)
 		{
@@ -95,7 +114,23 @@ namespace System.ServiceModel.Discovery
 
 		public bool TryReceive (TimeSpan timeout, out Message msg)
 		{
-			throw new NotImplementedException ();
+			ThrowIfDisposedOrNotOpen ();
+			msg = null;
+
+			byte [] bytes = null;
+			IPEndPoint ip = new IPEndPoint (IPAddress.Any, 0);
+			var ar = client.BeginReceive (delegate (IAsyncResult result) {
+				bytes = client.EndReceive (result, ref ip);
+			}, null);
+
+			if (!ar.IsCompleted && !ar.AsyncWaitHandle.WaitOne (timeout))
+				return false;
+			if (bytes.Length == 0)
+				return false;
+
+			// FIXME: give maxSizeOfHeaders
+			msg = message_encoder.ReadMessage (new MemoryStream (bytes), int.MaxValue);
+			return true;
 		}
 
 		protected override void OnAbort ()
@@ -144,9 +179,19 @@ namespace System.ServiceModel.Discovery
 				client = new UdpClient ();
 				client.Connect (RemoteAddress.Uri.Host, RemoteAddress.Uri.Port);
 			} else {
-				client = new UdpClient (LocalAddress.Uri.Host, LocalAddress.Uri.Port);
+				var ip = IPAddress.Parse (LocalAddress.Uri.Host);
+				bool isMulticast = NetworkInterface.GetAllNetworkInterfaces ().Any (nic => nic.SupportsMulticast && nic.GetIPProperties ().MulticastAddresses.Any (mca => mca.Address.Equals (ip)));
+				int port = LocalAddress.Uri.Port;
+				if (isMulticast) {
+					client = new UdpClient (new IPEndPoint (IPAddress.Any, port));
+					client.JoinMulticastGroup (ip, binding_element.TransportSettings.TimeToLive);
+				}
+				else
+					client = new UdpClient (new IPEndPoint (ip, port));
 			}
 
+			client.EnableBroadcast = true;
+
 			// FIXME: apply UdpTransportSetting here.
 		}
 		

+ 13 - 0
mcs/class/System.ServiceModel.Discovery/System.ServiceModel.Discovery.Udp/UdpTransportBindingElement.cs

@@ -33,17 +33,30 @@ namespace System.ServiceModel.Discovery
 	internal class UdpTransportBindingElement : TransportBindingElement
 	{
 		public UdpTransportBindingElement ()
+			: this (new UdpTransportSettings ())
 		{
 		}
 		
+		public UdpTransportBindingElement (UdpTransportSettings settings)
+		{
+			this.settings = settings ?? new UdpTransportSettings ();
+		}
+		
 		private UdpTransportBindingElement (UdpTransportBindingElement other)
 		{
+			settings = new UdpTransportSettings (other.settings);
 		}
 		
 		public override string Scheme {
 			get { return "soap.udp"; }
 		}
 		
+		UdpTransportSettings settings;
+
+		public UdpTransportSettings TransportSettings {
+			get { return settings; }
+		}
+
 		public override BindingElement Clone ()
 		{
 			return new UdpTransportBindingElement (this);

+ 12 - 0
mcs/class/System.ServiceModel.Discovery/System.ServiceModel.Discovery/UdpTransportSettings.cs

@@ -46,6 +46,18 @@ namespace System.ServiceModel.Discovery
 			TimeToLive = 1;
 		}
 
+		internal UdpTransportSettings (UdpTransportSettings source)
+		{
+			DuplicateMessageHistoryLength = source.DuplicateMessageHistoryLength;
+			MaxBufferPoolSize = source.MaxBufferPoolSize;
+			MaxMulticastRetransmitCount = source.MaxMulticastRetransmitCount;
+			MaxPendingMessageCount = source.MaxPendingMessageCount;
+			MaxReceivedMessageSize = source.MaxReceivedMessageSize;
+			MaxUnicastRetransmitCount = source.MaxUnicastRetransmitCount;
+			SocketReceiveBufferSize = source.SocketReceiveBufferSize;
+			TimeToLive = source.TimeToLive;
+		}
+
 		public int DuplicateMessageHistoryLength { get; set; }
 		public long MaxBufferPoolSize { get; set; }
 		public int MaxMulticastRetransmitCount { get; set; }