**** Merged from MCS ****
[mono-project.git] / mcs / class / System / System.Net / EndpointPermission.cs
blob434ba912fde79834108fce0da75389622f00b1d4
1 //
2 // System.Net.EndpointPermission.cs
3 //
4 // Author:
5 // Lawrence Pit (loz@cable.a2000.nl)
6 //
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Collections;
31 using System.Security;
32 using System.Security.Permissions;
34 namespace System.Net
36 [Serializable]
37 public class EndpointPermission // too bad about the lowercase p, not consistent with IPEndPoint ;)
39 private static char [] dot_char = new char [] { '.' };
41 // Fields
42 private string hostname;
43 private int port;
44 private TransportType transport;
46 private bool resolved;
47 private bool hasWildcard;
48 private IPAddress [] addresses;
50 // Constructors
51 internal EndpointPermission (string hostname,
52 int port,
53 TransportType transport) : base ()
55 if (hostname == null)
56 throw new ArgumentNullException ("hostname");
57 this.hostname = hostname;
58 this.port = port;
59 this.transport = transport;
60 this.resolved = false;
61 this.hasWildcard = false;
62 this.addresses = null;
65 // Properties
67 public string Hostname {
68 get { return hostname; }
71 public int Port {
72 get { return port; }
75 public TransportType Transport {
76 get { return transport; }
79 // Methods
81 public override bool Equals (object obj)
83 EndpointPermission epp = obj as EndpointPermission;
84 return ((epp != null) &&
85 (this.port == epp.port) &&
86 (this.transport == epp.transport) &&
87 (String.Compare (this.hostname, epp.hostname, true) == 0));
90 public override int GetHashCode ()
92 return ToString ().GetHashCode ();
95 public override string ToString ()
97 return hostname + "#" + port + "#" + (int) transport;
100 // Internal & Private Methods
102 internal bool IsSubsetOf (EndpointPermission perm)
104 if (perm == null)
105 return false;
107 if (perm.port != SocketPermission.AllPorts &&
108 this.port != perm.port)
109 return false;
111 if (perm.transport != TransportType.All &&
112 this.transport != perm.transport)
113 return false;
115 this.Resolve ();
116 perm.Resolve ();
118 if (this.hasWildcard) {
119 if (perm.hasWildcard)
120 return IsSubsetOf (this.hostname, perm.hostname);
121 else
122 return false;
125 if (this.addresses == null)
126 return false;
128 if (perm.hasWildcard)
129 // a bit dubious... should they all be a subset or is one
130 // enough in this case?
131 foreach (IPAddress addr in this.addresses)
132 if (IsSubsetOf (addr.ToString (), perm.hostname))
133 return true;
135 if (perm.addresses == null)
136 return false;
138 // a bit dubious... should they all be a subset or is one
139 // enough in this case?
140 foreach (IPAddress addr in perm.addresses)
141 if (IsSubsetOf (this.hostname, addr.ToString ()))
142 return true;
144 return false;
147 private bool IsSubsetOf (string addr1, string addr2)
149 string [] h1 = addr1.Split (dot_char);
150 string [] h2 = addr2.Split (dot_char);
152 for (int i = 0; i < 4; i++) {
153 int part1 = ToNumber (h1 [i]);
154 if (part1 == -1)
155 return false;
157 int part2 = ToNumber (h2 [i]);
158 if (part2 == -1)
159 return false;
160 if (part1 != part2 && part2 != 256)
161 return false;
163 return true;
166 internal EndpointPermission Intersect (EndpointPermission perm)
168 if (perm == null)
169 return null;
171 int _port;
172 if (this.port == perm.port)
173 _port = this.port;
174 else if (this.port == SocketPermission.AllPorts)
175 _port = perm.port;
176 else if (perm.port == SocketPermission.AllPorts)
177 _port = this.port;
178 else
179 return null;
181 TransportType _transport;
182 if (this.transport == perm.transport)
183 _transport = this.transport;
184 else if (this.transport == TransportType.All)
185 _transport = perm.transport;
186 else if (perm.transport == TransportType.All)
187 _transport = this.transport;
188 else
189 return null;
191 string _hostname = IntersectHostname (perm);
193 if (_hostname == null)
194 return null;
196 if (!this.hasWildcard)
197 return this;
199 if (!perm.hasWildcard)
200 return perm;
202 EndpointPermission newperm = new EndpointPermission (_hostname, _port, _transport);
203 newperm.hasWildcard = true;
204 newperm.resolved = true;
205 return newperm;
208 private string IntersectHostname (EndpointPermission perm)
210 if (this.hostname == perm.hostname)
211 return this.hostname;
213 this.Resolve ();
214 perm.Resolve ();
216 string _hostname = null;
218 if (this.hasWildcard) {
219 if (perm.hasWildcard) {
220 _hostname = Intersect (this.hostname, perm.hostname);
221 } else if (perm.addresses != null) {
222 for (int j = 0; j < perm.addresses.Length; j++) {
223 _hostname = Intersect (this.hostname, perm.addresses [j].ToString ());
224 if (_hostname != null)
225 break;
228 } else if (this.addresses != null) {
229 for (int i = 0; i < this.addresses.Length; i++) {
230 string thisaddr = this.addresses [i].ToString ();
231 if (perm.hasWildcard) {
232 _hostname = Intersect (thisaddr, perm.hostname);
233 } else if (perm.addresses != null) {
234 for (int j = 0; j < perm.addresses.Length; j++) {
235 _hostname = Intersect (thisaddr, perm.addresses [j].ToString ());
236 if (_hostname != null)
237 break;
243 return _hostname;
246 // alas, currently we'll only support IPv4 as that's MS.Net behaviour
247 // returns null when both host strings do not intersect
248 private string Intersect (string addr1, string addr2)
250 string [] h1 = addr1.Split (dot_char);
251 string [] h2 = addr2.Split (dot_char);
253 string [] s = new string [7];
254 for (int i = 0; i < 4; i++) {
255 int part1 = ToNumber (h1 [i]);
256 if (part1 == -1)
257 return null;
259 int part2 = ToNumber (h2 [i]);
260 if (part2 == -1)
261 return null;
263 if (part1 == 256)
264 s [i << 1] = (part2 == 256) ? "*" : String.Empty + part2;
265 else if (part2 == 256)
266 s [i << 1] = (part1 == 256) ? "*" : String.Empty + part1;
267 else if (part1 == part2)
268 s [i << 1] = String.Empty + part1;
269 else
270 return null;
273 s [1] = s [3] = s [5] = ".";
274 return String.Concat (s);
277 // returns 256 if value is a '*' character
278 // returns -1 if value isn't a number between 0 and 255
279 private int ToNumber (string value)
281 if (value == "*")
282 return 256;
284 int len = value.Length;
285 if (len < 1 || len > 3)
286 return -1;
288 int val = 0;
289 for (int i = 0; i < len; i++) {
290 char c = value [i];
291 if ('0' <= c && c <= '9')
292 val = checked (val * 10 + (c - '0'));
293 else
294 return -1;
297 return val <= 255 ? val : -1;
300 internal void Resolve ()
302 if (resolved)
303 return;
305 bool isHostname = false;
306 bool hasWildcard = false;
307 this.addresses = null;
309 string [] s = hostname.Split (dot_char);
311 if (s.Length != 4) {
312 isHostname = true;
313 } else {
314 for (int i = 0; i < 4; i++) {
315 int quad = ToNumber (s [i]);
316 if (quad == -1) {
317 isHostname = true;
318 break;
320 if (quad == 256)
321 hasWildcard = true;
325 if (isHostname) {
326 this.hasWildcard = false;
327 try {
328 this.addresses = Dns.GetHostByName (hostname).AddressList;
329 } catch (System.Net.Sockets.SocketException) {
331 } else {
332 this.hasWildcard = hasWildcard;
333 if (!hasWildcard) {
334 addresses = new IPAddress [1];
335 addresses [0] = IPAddress.Parse (hostname);
339 this.resolved = true;
342 internal void UndoResolve ()
344 resolved = false;