@@ -150,6 +150,81 @@ public void MulticastInterface_Set_InvalidIndex_Throws()
150150 }
151151 }
152152
153+ [ OuterLoop ] // TODO: Issue #11345
154+ [ Fact ]
155+ public async Task MulticastInterface_Set_IPv6_AnyInterface_Succeeds ( )
156+ {
157+ if ( PlatformDetection . IsFedora || PlatformDetection . IsRedHatFamily7 || PlatformDetection . IsOSX )
158+ {
159+ return ; // [ActiveIssue(24008)]
160+ }
161+
162+ // On all platforms, index 0 means "any interface"
163+ await MulticastInterface_Set_IPv6_Helper ( 0 ) ;
164+ }
165+
166+ [ OuterLoop ] // TODO: Issue #11345
167+ [ Fact ]
168+ [ PlatformSpecific ( TestPlatforms . Windows ) ]
169+ [ ActiveIssue ( 21327 , TargetFrameworkMonikers . Uap ) ] // UWP Apps are forbidden to send network traffic to the local Computer.
170+ public async void MulticastInterface_Set_IPv6_Loopback_Succeeds ( )
171+ {
172+ // On Windows, we can apparently assume interface 1 is "loopback." On other platforms, this is not a
173+ // valid assumption. We could maybe use NetworkInterface.LoopbackInterfaceIndex to get the index, but
174+ // this would introduce a dependency on System.Net.NetworkInformation, which depends on System.Net.Sockets,
175+ // which is what we're testing here.... So for now, we'll just assume "loopback == 1" and run this on
176+ // Windows only.
177+ await MulticastInterface_Set_IPv6_Helper ( 1 ) ;
178+ }
179+
180+ private async Task MulticastInterface_Set_IPv6_Helper ( int interfaceIndex )
181+ {
182+ IPAddress multicastAddress = IPAddress . Parse ( "ff11::1:1" ) ;
183+ string message = "hello" ;
184+ int port ;
185+
186+ using ( Socket receiveSocket = CreateBoundUdpIPv6Socket ( out port ) ,
187+ sendSocket = new Socket ( AddressFamily . InterNetworkV6 , SocketType . Dgram , ProtocolType . Udp ) )
188+ {
189+ receiveSocket . ReceiveTimeout = 1000 ;
190+ receiveSocket . SetSocketOption ( SocketOptionLevel . IPv6 , SocketOptionName . AddMembership , new IPv6MulticastOption ( multicastAddress , interfaceIndex ) ) ;
191+
192+ // https://github.com/Microsoft/BashOnWindows/issues/990
193+ if ( ! PlatformDetection . IsWindowsSubsystemForLinux )
194+ {
195+ sendSocket . SetSocketOption ( SocketOptionLevel . IPv6 , SocketOptionName . MulticastInterface , interfaceIndex ) ;
196+ }
197+
198+ var receiveBuffer = new byte [ 1024 ] ;
199+ var receiveTask = receiveSocket . ReceiveAsync ( new ArraySegment < byte > ( receiveBuffer ) , SocketFlags . None ) ;
200+
201+ for ( int i = 0 ; i < TestSettings . UDPRedundancy ; i ++ )
202+ {
203+ sendSocket . SendTo ( Encoding . UTF8 . GetBytes ( message ) , new IPEndPoint ( multicastAddress , port ) ) ;
204+ }
205+
206+ var cts = new CancellationTokenSource ( ) ;
207+ Assert . True ( await Task . WhenAny ( receiveTask , Task . Delay ( 20_000 , cts . Token ) ) == receiveTask , "Waiting for received data timed out" ) ;
208+ cts . Cancel ( ) ;
209+
210+ int bytesReceived = await receiveTask ;
211+ string receivedMessage = Encoding . UTF8 . GetString ( receiveBuffer , 0 , bytesReceived ) ;
212+
213+ Assert . Equal ( receivedMessage , message ) ;
214+ }
215+ }
216+
217+ [ Fact ]
218+ public void MulticastInterface_Set_IPv6_InvalidIndex_Throws ( )
219+ {
220+ int interfaceIndex = 31415 ;
221+ using ( Socket s = new Socket ( AddressFamily . InterNetworkV6 , SocketType . Dgram , ProtocolType . Udp ) )
222+ {
223+ Assert . Throws < SocketException > ( ( ) =>
224+ s . SetSocketOption ( SocketOptionLevel . IPv6 , SocketOptionName . MulticastInterface , interfaceIndex ) ) ;
225+ }
226+ }
227+
153228 [ OuterLoop ] // TODO: Issue #11345
154229 [ ConditionalTheory ( typeof ( PlatformDetection ) , nameof ( PlatformDetection . IsNotWindowsSubsystemForLinux ) ) ] // In WSL, the connect() call fails immediately.
155230 [ InlineData ( false ) ]
@@ -215,6 +290,21 @@ private static Socket CreateBoundUdpSocket(out int localPort)
215290 return receiveSocket ;
216291 }
217292
293+ // Create an Udp Socket and binds it to an available port
294+ private static Socket CreateBoundUdpIPv6Socket ( out int localPort )
295+ {
296+ Socket receiveSocket = new Socket ( AddressFamily . InterNetworkV6 , SocketType . Dgram , ProtocolType . Udp ) ;
297+
298+ // sending a message will bind the socket to an available port
299+ string sendMessage = "dummy message" ;
300+ int port = 54320 ;
301+ IPAddress multicastAddress = IPAddress . Parse ( "ff11::1:1" ) ;
302+ receiveSocket . SendTo ( Encoding . UTF8 . GetBytes ( sendMessage ) , new IPEndPoint ( multicastAddress , port ) ) ;
303+
304+ localPort = ( receiveSocket . LocalEndPoint as IPEndPoint ) . Port ;
305+ return receiveSocket ;
306+ }
307+
218308 [ Theory ]
219309 [ InlineData ( null , null , null , true ) ]
220310 [ InlineData ( null , null , false , true ) ]
0 commit comments