2003-05-21 Ben Maurer <bmaurer@users.sourceforge.net>
[mono.git] / mcs / class / System / System.Net / EndpointPermission.cs
1 //\r
2 // System.Net.EndpointPermission.cs\r
3 //\r
4 // Author:\r
5 //   Lawrence Pit (loz@cable.a2000.nl)\r
6 //\r
7 \r
8 using System;\r
9 using System.Collections;\r
10 using System.Security;\r
11 using System.Security.Permissions;\r
12 \r
13 namespace System.Net\r
14 {\r
15         [Serializable]\r
16         public class EndpointPermission // too bad about the lowercase p, not consistent with IPEndPoint ;)\r
17         {\r
18                 private static char [] dot_char = new char [] { '.' };\r
19                 \r
20                 // Fields\r
21                 private string hostname;\r
22                 private int port;\r
23                 private TransportType transport;\r
24 \r
25                 private bool resolved;          \r
26                 private bool hasWildcard;\r
27                 private IPAddress [] addresses;\r
28                 \r
29                 // Constructors\r
30                 internal EndpointPermission (string hostname, \r
31                                              int port, \r
32                                              TransportType transport) : base () \r
33                 {                       \r
34                         if (hostname == null)\r
35                                 throw new ArgumentNullException ("hostname");\r
36                         this.hostname = hostname;\r
37                         this.port = port;\r
38                         this.transport = transport;\r
39                         this.resolved = false;\r
40                         this.hasWildcard = false;\r
41                         this.addresses = null;\r
42                 }               \r
43                 \r
44                 // Properties\r
45 \r
46                 public string Hostname {\r
47                         get { return hostname; }\r
48                 }\r
49 \r
50                 public int Port {\r
51                         get { return port; }\r
52                 }\r
53                 \r
54                 public TransportType Transport {\r
55                         get { return transport; }\r
56                 }\r
57                 \r
58                 // Methods\r
59                 \r
60                 public override bool Equals (object obj) \r
61                 {\r
62                         EndpointPermission epp = obj as EndpointPermission;\r
63                         return ((epp != null) &&\r
64                                 (this.port == epp.port) &&\r
65                                 (this.transport == epp.transport) &&\r
66                                 (String.Compare (this.hostname, epp.hostname, true) == 0));\r
67                 }\r
68                 \r
69                 public override int GetHashCode () \r
70                 {\r
71                         return ToString ().GetHashCode ();\r
72                 }\r
73                 \r
74                 public override string ToString () \r
75                 {\r
76                         return hostname + "#" + port + "#" + (int) transport;\r
77                 }\r
78                 \r
79                 // Internal & Private Methods\r
80                 \r
81                 internal bool IsSubsetOf (EndpointPermission perm) \r
82                 {\r
83                         if (perm == null)\r
84                                 return false;\r
85                         \r
86                         if (perm.port != SocketPermission.AllPorts &&\r
87                             this.port != perm.port)\r
88                                 return false;\r
89                         \r
90                         if (perm.transport != TransportType.All &&\r
91                             this.transport != perm.transport)\r
92                                 return false;\r
93                         \r
94                         this.Resolve ();\r
95                         perm.Resolve ();\r
96                         \r
97                         if (this.hasWildcard) {\r
98                                 if (perm.hasWildcard)\r
99                                         return IsSubsetOf (this.hostname, perm.hostname);\r
100                                 else \r
101                                         return false;\r
102                         } \r
103                         \r
104                         if (this.addresses == null) \r
105                                 return false;\r
106                         \r
107                         if (perm.hasWildcard) \r
108                                 // a bit dubious... should they all be a subset or is one \r
109                                 // enough in this case?\r
110                                 foreach (IPAddress addr in this.addresses)\r
111                                         if (IsSubsetOf (addr.ToString (), perm.hostname))\r
112                                                 return true;\r
113                                 \r
114                         if (perm.addresses == null) \r
115                                 return false;\r
116                                 \r
117                         // a bit dubious... should they all be a subset or is one \r
118                         // enough in this case?\r
119                         foreach (IPAddress addr in perm.addresses)\r
120                                 if (IsSubsetOf (this.hostname, addr.ToString ())) \r
121                                         return true;    \r
122                                         \r
123                         return false;           \r
124                 }               \r
125                 \r
126                 private bool IsSubsetOf (string addr1, string addr2)\r
127                 {\r
128                         string [] h1 = addr1.Split (dot_char);          \r
129                         string [] h2 = addr2.Split (dot_char);\r
130                                 \r
131                         for (int i = 0; i < 4; i++) {\r
132                                 int part1 = ToNumber (h1 [i]);\r
133                                 if (part1 == -1) \r
134                                         return false;                           \r
135 \r
136                                 int part2 = ToNumber (h2 [i]);\r
137                                 if (part2 == -1)\r
138                                         return false;                           \r
139                                 if (part1 != part2 && part2 != 256)\r
140                                         return false;\r
141                         }\r
142                         return true;\r
143                 }\r
144                 \r
145                 internal EndpointPermission Intersect (EndpointPermission perm) \r
146                 {\r
147                         if (perm == null)\r
148                                 return null;\r
149                         \r
150                         int _port;\r
151                         if (this.port == perm.port)\r
152                                 _port = this.port;\r
153                         else if (this.port == SocketPermission.AllPorts)\r
154                                 _port = perm.port;\r
155                         else if (perm.port == SocketPermission.AllPorts)\r
156                                 _port = this.port;\r
157                         else\r
158                                 return null;\r
159 \r
160                         TransportType _transport;\r
161                         if (this.transport == perm.transport)\r
162                                 _transport = this.transport;\r
163                         else if (this.transport == TransportType.All)\r
164                                 _transport = perm.transport;\r
165                         else if (perm.transport == TransportType.All)\r
166                                 _transport = this.transport;\r
167                         else\r
168                                 return null;\r
169 \r
170                         string _hostname = IntersectHostname (perm);                                            \r
171                         \r
172                         if (_hostname == null)\r
173                                 return null;\r
174 \r
175                         if (!this.hasWildcard)\r
176                                 return this;\r
177                                 \r
178                         if (!perm.hasWildcard)\r
179                                 return perm;\r
180                                 \r
181                         EndpointPermission newperm = new EndpointPermission (_hostname, _port, _transport);\r
182                         newperm.hasWildcard = true;\r
183                         newperm.resolved = true;\r
184                         return newperm;\r
185                 }\r
186                 \r
187                 private string IntersectHostname (EndpointPermission perm)\r
188                 {\r
189                         if (this.hostname == perm.hostname)\r
190                                 return this.hostname;\r
191                                 \r
192                         this.Resolve ();\r
193                         perm.Resolve ();\r
194                         \r
195                         string _hostname = null;\r
196                         \r
197                         if (this.hasWildcard) {\r
198                                 if (perm.hasWildcard) {\r
199                                         _hostname = Intersect (this.hostname, perm.hostname);\r
200                                 } else if (perm.addresses != null) {\r
201                                         for (int j = 0; j < perm.addresses.Length; j++) {\r
202                                                 _hostname = Intersect (this.hostname, perm.addresses [j].ToString ());\r
203                                                 if (_hostname != null) \r
204                                                         break;\r
205                                         }\r
206                                 }\r
207                         } else if (this.addresses != null) {\r
208                                 for (int i = 0; i < this.addresses.Length; i++) {\r
209                                         string thisaddr = this.addresses [i].ToString ();\r
210                                         if (perm.hasWildcard) {\r
211                                                 _hostname = Intersect (thisaddr, perm.hostname);\r
212                                         } else if (perm.addresses != null) {\r
213                                                 for (int j = 0; j < perm.addresses.Length; j++) {\r
214                                                         _hostname = Intersect (thisaddr, perm.addresses [j].ToString ());\r
215                                                         if (_hostname != null) \r
216                                                                 break;\r
217                                                 }\r
218                                         }\r
219                                 }\r
220                         }\r
221                         \r
222                         return _hostname;\r
223                 }\r
224                 \r
225                 // alas, currently we'll only support IPv4 as that's MS.Net behaviour\r
226                 // returns null when both host strings do not intersect\r
227                 private string Intersect (string addr1, string addr2)\r
228                 {\r
229                         string [] h1 = addr1.Split (dot_char);          \r
230                         string [] h2 = addr2.Split (dot_char);\r
231                                 \r
232                         string [] s = new string [7];\r
233                         for (int i = 0; i < 4; i++) {\r
234                                 int part1 = ToNumber (h1 [i]);\r
235                                 if (part1 == -1) \r
236                                         return null;                            \r
237 \r
238                                 int part2 = ToNumber (h2 [i]);\r
239                                 if (part2 == -1)\r
240                                         return null;                            \r
241 \r
242                                 if (part1 == 256) \r
243                                         s [i << 1] = (part2 == 256) ? "*" : String.Empty + part2;\r
244                                 else if (part2 == 256)\r
245                                         s [i << 1] = (part1 == 256) ? "*" : String.Empty + part1;                               \r
246                                 else if (part1 == part2)\r
247                                         s [i << 1] = String.Empty + part1;\r
248                                 else\r
249                                         return null;\r
250                         }\r
251                         \r
252                         s [1] = s [3] = s [5] = ".";\r
253                         return String.Concat (s);\r
254                 }\r
255                 \r
256                 // returns 256 if value is a '*' character\r
257                 // returns -1 if value isn't a number between 0 and 255         \r
258                 private int ToNumber (string value)\r
259                 {\r
260                         if (value == "*")\r
261                                 return 256;\r
262                                 \r
263                         int len = value.Length;\r
264                         if (len < 1 || len > 3)\r
265                                 return -1;\r
266                                 \r
267                         int val = 0;                            \r
268                         for (int i = 0; i < len; i++) {\r
269                                 char c = value [i];\r
270                                 if ('0' <= c && c <= '9') \r
271                                         val = checked (val * 10 + (c - '0'));\r
272                                 else\r
273                                         return -1;\r
274                         }\r
275                         \r
276                         return val <= 255 ? val : -1;\r
277                 }\r
278 \r
279                 internal void Resolve ()\r
280                 {\r
281                         if (resolved)   \r
282                                 return;\r
283                                 \r
284                         bool isHostname = false;                                \r
285                         bool hasWildcard = false;\r
286                         this.addresses = null;\r
287                         \r
288                         string [] s = hostname.Split (dot_char);\r
289 \r
290                         if (s.Length != 4) {\r
291                                 isHostname = true;\r
292                         } else {\r
293                                 for (int i = 0; i < 4; i++) {\r
294                                         int quad = ToNumber (s [i]);\r
295                                         if (quad == -1) {\r
296                                                 isHostname = true;\r
297                                                 break;\r
298                                         }\r
299                                         if (quad == 256)\r
300                                                 hasWildcard = true;\r
301                                 }\r
302                         }\r
303                         \r
304                         if (isHostname) {\r
305                                 this.hasWildcard = false;\r
306                                 try {\r
307                                         this.addresses = Dns.GetHostByName (hostname).AddressList;\r
308                                 } catch (System.Net.Sockets.SocketException) {                                  \r
309                                 }\r
310                         } else {\r
311                                 this.hasWildcard = hasWildcard;\r
312                                 if (!hasWildcard) {\r
313                                         addresses = new IPAddress [1];\r
314                                         addresses [0] = IPAddress.Parse (hostname);\r
315                                 }\r
316                         }\r
317                         \r
318                         this.resolved = true;                           \r
319                 }\r
320                 \r
321                 internal void UndoResolve ()\r
322                 {\r
323                         resolved = false;\r
324                 }\r
325         }\r
326 }\r