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.

No comments