I wanted to perform discovery (enumerating, listing, whatever you call it) on SQL servers on a network, without having to resort to interop. I nearly gave up.
A major problem is that it doesn’t seem to be possible to perform an UDP broadcast using System.Net.Socket.Socket
Using this code:
Imports System.Net
Imports System.Net.Sockets
Imports System.Net.SocketPermission
Module UDPBroadcastTest
Public Function ByteArrayToIPAddress(ByVal ByteArray As Byte()) As IPAddress
Return New IPAddress(Convert.ToInt64(BitConverter.ToUInt32(ByteArray, 0)))
End Function
Sub Main()
Dim IP As IPAddress = ByteArrayToIPAddress(New Byte() {255, 255, 255, 255})
Dim Port As Short = 12345
Dim SendSocket As New Net.Sockets.Socket _
( _
IP.AddressFamily, _
Sockets.SocketType.Dgram, _
Sockets.ProtocolType.Udp _
)
Dim SendPermission As New SocketPermission _
( _
Security.Permissions.PermissionState.Unrestricted _
)
SendPermission.Demand()
SendSocket.SendTo(New Byte() {0}, New IPEndPoint(IP, Port))
End Sub
End Module
I get:
System.Net.Sockets.SocketException: An attempt was made to access a socket in a way forbidden by its access permissions at System.Net.Sockets.Socket.SendTo(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, EndPoint remoteEP) at System.Net.Sockets.Socket.SendTo(Byte[] buffer, EndPoint remoteEP)
I think this is a bug, but I can’t find anyone else trying to do it, so perhaps I did something wrong.
After reaching this brick wall, I decided to go back to UDPClient. Using UDPClient gives no permission error, but calling Receive blocks. There is no obvious way of doing a non-blocking receive. So I tried putting the code which calls Receive into its own thread, and aborting it after a timeout. Naughty, but should work. It doesn’t. While Receive is blocking, aborting the thread doesn’t work. Another bug in the framework?
Finally, I thought back to what I really wanted: A non-blocking Receive. The UDPClient object had to be using a Socket internally, so if I could get to that Socket, I could Select on it and only call Receive when I knew it wouldn’t block.
The way I got to the underlying socket was by using the age-old inherit-from-it trick:
Private Class SocketExposingUDPClient
Inherits UdpClient
Public Function Socket() As Socket
Return Me.Client
End Function
End Class
Success! One list of SQL Server instances (with IPs), using only pure .NET code.
N.B.: Whidbey makes this work with no hassle.