For Socket based communications in Silverlight, we need to run Policy Server at Socket Listening host. Policy Server will send the Policy XML file to silverlight client similar to flash crossdomain.xml file, which Silverlight also uses for its HTTP request. Without Policy Server, Silverlight sockets cannot connect to a Server Application.
The Crossdomain.xml file can be directly accessed by Clients using HTTP request from related web server, where as for sockets based communication server, web server is not in the picture. So for security purposes, similar to crossdomain file, there needs a policy file to be downloaded & which will be issued by Policy Server.
1. Our Policy Server listens in Port: 943.
2. Silverlight client will connect to our policy server & send a request "<policy-file-request/>"
3. Once this request is received, Policy Server should send the Policy XML file in that connection & close that connection request.
Imports System
Imports System.IO
Imports System.Net.Sockets
Imports System.Text
Public Class PolicyServerService
Public sSocket As Socket
Private PolicyFile As String = String.Empty
Private Const POLICYREQUEST As String = "<policy-file-request/>"
Private Const POLICYPORT As Integer = 943
Private Const POLICYFILENAME As String = "clientaccesspolicy.xml"
Public Sub New()
' Read Policy File details
PolicyFile = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) & "\" & POLICYFILENAME
' Establish the local endpoint for the socket.
Dim ipLocal As New System.Net.IPEndPoint(System.Net.IPAddress.Any, POLICYPORT)
sSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
sSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 0)
sSocket.Bind(ipLocal)
sSocket.Listen(10)
'Start an asynchronous socket to listen for connections.
sSocket.BeginAccept(New AsyncCallback(AddressOf onConnect), Nothing)
End Sub
Private Sub onConnect(ByVal asyn As IAsyncResult)
Dim objPolicyConnection As New PolicyConnection
Try
With objPolicyConnection
.cSocket = sSocket.EndAccept(asyn)
.cSocket.BeginReceive(.buffer, 0, .buffer.Length, SocketFlags.None, New AsyncCallback(AddressOf onDataArrival), objPolicyConnection)
End With
'continue listen for connections.
sSocket.BeginAccept(New AsyncCallback(AddressOf onConnect), Nothing)
Catch exNull As System.NullReferenceException
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
End Sub
Private Sub onDataArrival(ByVal asyn As IAsyncResult)
Dim strData As String = String.Empty
Dim policyFile As String = String.Empty
Dim ibRead As Integer = 0
Dim objPolicyConnection As PolicyConnection = CType(asyn.AsyncState, PolicyConnection)
Try
With objPolicyConnection
If .cSocket.Connected Then ibRead = .cSocket.EndReceive(asyn)
If ibRead > 0 Then
receivedText.Append(Encoding.ASCII.GetString(.buffer, 0, ibRead))
strData = .receivedText.ToString()
If strData.Length < POLICYREQUEST.Length Then
' if not full request received
.cSocket.BeginReceive(.buffer, 0, .buffer.Length, SocketFlags.None, New AsyncCallback(AddressOf onDataArrival), objPolicyConnection)
Return
End If
If StringComparer.InvariantCultureIgnoreCase.Compare(strData, POLICYREQUEST) <> 0 Then
' if not matching with Policy Request, then exit
.cSocket.Close()
Return
End If
'Sending Policy File
.cSocket.BeginSendFile(policyFile, New AsyncCallback(AddressOf onSend), objPolicyConnection)
End With
Catch ex As Exception
objPolicyConnection.cSocket.Close()
End Try
End Sub
Private Sub onSend(ByVal asyn As IAsyncResult)
Dim objPolicyConnection As PolicyConnection = CType(asyn.AsyncState, PolicyConnection)
' Finish File Send & Close Connection since no further communication needed
Try
objPolicyConnection.cSocket.EndSendFile(asyn)
Catch ex As Exception
Finally
objPolicyConnection.cSocket.Close()
End Try
End Sub
End Class
Public Class PolicyConnection
Public cSocket As Socket
Private Const POLICYREQUEST As String ="<policy-file-request/>"
Public buffer(POLICYREQUEST.Length) As Byte
Public receivedText As New StringBuilder
End Class