2 // Socket Policy Server (sockpol)
5 // Moonlight List (moonlight-list@lists.ximian.com)
7 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
9 // Based on XSP source code (ApplicationServer.cs and XSPWebSource.cs)
11 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
12 // Lluis Sanchez Gual (lluis@ximian.com)
14 // Copyright (c) Copyright 2002-2007 Novell, Inc
16 // Permission is hereby granted, free of charge, to any person obtaining
17 // a copy of this software and associated documentation files (the
18 // "Software"), to deal in the Software without restriction, including
19 // without limitation the rights to use, copy, modify, merge, publish,
20 // distribute, sublicense, and/or sell copies of the Software, and to
21 // permit persons to whom the Software is furnished to do so, subject to
22 // the following conditions:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using System
.Net
.Sockets
;
41 using System
.Threading
;
43 class SocketPolicyServer
{
45 const string PolicyFileRequest
= "<policy-file-request/>";
46 static byte[] request
= Encoding
.UTF8
.GetBytes (PolicyFileRequest
);
47 private byte[] policy
;
49 private Socket listen_socket
;
50 private Thread runner
;
52 private AsyncCallback accept_cb
;
55 public Request (Socket s
)
58 // the only answer to a single request (so it's always the same length)
59 Buffer
= new byte [request
.Length
];
63 public Socket Socket { get; private set; }
64 public byte[] Buffer { get; set; }
65 public int Length { get; set; }
68 public SocketPolicyServer (string xml
)
70 // transform the policy to a byte array (a single time)
71 policy
= Encoding
.UTF8
.GetBytes (xml
);
77 listen_socket
= new Socket (AddressFamily
.InterNetwork
, SocketType
.Stream
, ProtocolType
.Tcp
);
78 listen_socket
.Bind (new IPEndPoint (IPAddress
.Any
, 943));
79 listen_socket
.Listen (500);
80 listen_socket
.Blocking
= false;
82 catch (SocketException se
) {
83 // Most common mistake: port 943 is not user accessible on unix-like operating systems
84 if (se
.SocketErrorCode
== SocketError
.AccessDenied
) {
85 Console
.WriteLine ("NOTE: must be run as root since the server listen to port 943");
88 Console
.WriteLine (se
);
93 runner
= new Thread (new ThreadStart (RunServer
));
100 accept_cb
= new AsyncCallback (OnAccept
);
101 listen_socket
.BeginAccept (accept_cb
, null);
103 while (true) // Just sleep until we're aborted.
104 Thread
.Sleep (1000000);
107 void OnAccept (IAsyncResult ar
)
109 Socket accepted
= null;
111 accepted
= listen_socket
.EndAccept (ar
);
114 listen_socket
.BeginAccept (accept_cb
, null);
117 if (accepted
== null)
120 accepted
.Blocking
= true;
122 Request request
= new Request (accepted
);
123 accepted
.BeginReceive (request
.Buffer
, 0, request
.Length
, SocketFlags
.None
, new AsyncCallback (OnReceive
), request
);
126 void OnReceive (IAsyncResult ar
)
128 Request r
= (ar
.AsyncState
as Request
);
129 Socket socket
= r
.Socket
;
131 r
.Length
+= socket
.EndReceive (ar
);
133 // compare incoming data with expected request
134 for (int i
=0; i
< r
.Length
; i
++) {
135 if (r
.Buffer
[i
] != request
[i
]) {
136 // invalid request, close socket
142 if (r
.Length
== request
.Length
) {
143 // request complete, send policy
144 socket
.BeginSend (policy
, 0, policy
.Length
, SocketFlags
.None
, new AsyncCallback (OnSend
), socket
);
146 // continue reading from socket
147 socket
.BeginReceive (r
.Buffer
, r
.Length
, request
.Length
- r
.Length
, SocketFlags
.None
,
148 new AsyncCallback (OnReceive
), ar
.AsyncState
);
151 // if anything goes wrong we stop our connection by closing the socket
156 void OnSend (IAsyncResult ar
)
158 Socket socket
= (ar
.AsyncState
as Socket
);
162 // whatever happens we close the socket
171 listen_socket
.Close ();
174 const string AllPolicy
= @"<?xml version=""1.0"" encoding=""utf-8""?>
176 <cross-domain-access>
182 <socket-resource port=""4502-4534"" protocol=""tcp"" />
185 </cross-domain-access>
188 const string LocalPolicy
= @"<?xml version=""1.0"" encoding=""utf-8""?>
190 <cross-domain-access>
193 <domain uri=""file:///"" />
196 <socket-resource port=""4502-4534"" protocol=""tcp"" />
199 </cross-domain-access>
202 static int Main (string[] args
)
204 if (args
.Length
== 0) {
205 Console
.WriteLine ("sockpol [--all | --local | --file policy]");
206 Console
.WriteLine ("\t--all Allow access to all URI on every port (4502-4534)");
207 Console
.WriteLine ("\t--local Allow local access on every port (4502-4534)");
211 string policy
= null;
217 policy
= LocalPolicy
;
220 if (args
.Length
< 2) {
221 Console
.WriteLine ("Missing policy file name after '--file'.");
224 string filename
= args
[1];
225 if (!File
.Exists (filename
)) {
226 Console
.WriteLine ("Could not find policy file '{0}'.", filename
);
229 using (StreamReader sr
= new StreamReader (filename
)) {
230 policy
= sr
.ReadToEnd ();
234 Console
.WriteLine ("Unknown option '{0}'.", args
[0]);
238 SocketPolicyServer server
= new SocketPolicyServer (policy
);
239 int result
= server
.Start ();
243 Console
.WriteLine ("Hit Return to stop the server.");