2002-04-15 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mcs / class / System / System.Net / IPAddress.cs
1 //
2 // System.Net.IPAddress.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 //
9
10 using System.Net.Sockets;
11 using System.Runtime.InteropServices;
12
13 using System;
14
15 namespace System.Net {
16
17         /// <remarks>
18         ///   Encapsulates an IP Address.
19         /// </remarks>
20         [Serializable]
21         public class IPAddress {
22                 // Don't change the name of this field without also
23                 // changing socket-io.c in the runtime
24                 // This will stored in network order
25                 private long address;
26
27                 public static readonly IPAddress Any=new IPAddress(0);
28                 public static readonly IPAddress Broadcast=new IPAddress(0xffffffff);
29                 public static readonly IPAddress Loopback=new IPAddress(0x7f000001);
30                 public static readonly IPAddress None=new IPAddress(0xffffffff);
31
32                 private static bool isLittleEndian;
33
34                 [StructLayout(LayoutKind.Explicit)]
35                 private struct EndianTest
36                 {
37                         [FieldOffset (0)] public byte b0;
38                         [FieldOffset (0)] public short s0;
39                 }
40
41                 static IPAddress ()
42                 {
43                         EndianTest typeEndian = new EndianTest ();
44                         typeEndian.s0 = 1;
45                         isLittleEndian = typeEndian.b0 == 1;
46                 }
47
48                 private static short SwapShort (short number)
49                 {
50                         return (short) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );
51                 }
52
53                 private static int SwapInt (int number)
54                 {
55                         byte b0 = (byte) ((number >> 24) & 0xFF);
56                         byte b1 = (byte) ((number >> 16) & 0xFF);
57                         byte b2 = (byte) ((number >> 8) & 0xFF);
58                         byte b3 = (byte) (number & 0xFF);
59                         return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24);
60                 }
61
62                 private static long SwapLong (long number)
63                 {
64                         byte b0 = (byte) ((number >> 56) & 0xFF);
65                         byte b1 = (byte) ((number >> 48) & 0xFF);
66                         byte b2 = (byte) ((number >> 40) & 0xFF);
67                         byte b3 = (byte) ((number >> 32) & 0xFF);
68                         byte b4 = (byte) ((number >> 24) & 0xFF);
69                         byte b5 = (byte) ((number >> 16) & 0xFF);
70                         byte b6 = (byte) ((number >> 8) & 0xFF);
71                         byte b7 = (byte) (number & 0xFF);
72                         return b0 + (b1 << 8) + (b2 << 16) + (b3 << 24) + (b4 << 32) + (b5 << 40) + (b6 << 48) + (b7 << 56);
73                 }
74
75                 public static short HostToNetworkOrder(short host) {
76                         if (!isLittleEndian)
77                                 return(host);
78
79                         return SwapShort (host);
80                 }
81
82                 public static int HostToNetworkOrder(int host) {
83                         if (!isLittleEndian)
84                                 return(host);
85
86                         return SwapInt (host);
87                 }
88                 
89                 public static long HostToNetworkOrder(long host) {
90                         if (!isLittleEndian)
91                                 return(host);
92
93                         return SwapLong (host);
94                 }
95
96                 public static short NetworkToHostOrder(short network) {
97                         if (!isLittleEndian)
98                                 return(network);
99
100                         return SwapShort (network);
101                 }
102
103                 public static int NetworkToHostOrder(int network) {
104                         if (!isLittleEndian)
105                                 return(network);
106
107                         return SwapInt (network);
108                 }
109
110                 public static long NetworkToHostOrder(long network) {
111                         if (!isLittleEndian)
112                                 return(network);
113
114                         return SwapLong (network);
115                 }
116                 
117                 /// <summary>
118                 ///   Constructor from a 32-bit constant.
119                 /// </summary>
120                 public IPAddress (long addr)
121                 {
122                         Address = addr;
123                 }
124
125                 public static IPAddress Parse(string ip)
126                 {
127                         if(ip == null)
128                                 throw new ArgumentNullException("null ip string");
129
130                         int pos = 0;
131                         int ndots = 0;
132                         char current;
133                         bool prevDigit = false;
134
135                         while (pos < ip.Length) {
136                                 current  = ip [pos++];
137                                 if (Char.IsDigit (current))
138                                         prevDigit = true;
139                                 else
140                                 if (current == '.') {
141                                         // No more than 3 dots. Doesn't allow ending with a dot.
142                                         if (++ndots > 3 || pos == ip.Length || prevDigit == false)
143                                                 throw new FormatException ("the string is not a valid ip");
144
145                                         prevDigit = false;
146                                 }
147                                 else if (!Char.IsDigit (current)) {
148                                         if (!Char.IsWhiteSpace (current))
149                                                 throw new FormatException ("the string is not a valid ip");
150
151                                         // The same as MS does
152                                         if (pos == 1) 
153                                                 return new IPAddress (0);
154
155                                         break;
156                                 }
157                         }
158
159                         if (ndots != 3)
160                                 throw new FormatException ("the string is not a valid ip");
161
162
163                         long a = 0;
164                         string [] ips = ip.Split (new char [] {'.'});
165                         for (int i = 0; i < ips.Length; i++)
166                                 a = (a << 8) |  (Byte.Parse(ips [i]));
167
168                         return (new IPAddress (a));
169                 }
170                 
171                 public long Address {
172                         get {
173                                 return (NetworkToHostOrder (address));
174                         }
175                         set {
176                         if (value < 0 || value > 0x00000000FFFFFFFF)
177                                 throw new ArgumentOutOfRangeException (
178                                         "the address must be between 0 and 0xFFFFFFFF");
179
180                                 address = HostToNetworkOrder (value);
181                         }
182                 }
183
184                 public AddressFamily AddressFamily {
185                         get {
186                                 return(AddressFamily.InterNetwork);
187                         }
188                 }
189                 
190                 
191                 /// <summary>
192                 ///   Used to tell whether an address is a loopback.
193                 ///   All IP addresses of the form 127.X.Y.Z, where X, Y, and Z are in 
194                 ///   the range 0-255, are loopback addresses.
195                 /// </summary>
196                 /// <param name="addr">Address to compare</param>
197                 /// <returns></returns>
198                 public static bool IsLoopback (IPAddress addr)
199                 {
200                         return (addr.address & 0xFF) == 127;
201                 }
202
203                 /// <summary>
204                 ///   Overrides System.Object.ToString to return
205                 ///   this object rendered in a quad-dotted notation
206                 /// </summary>
207                 public override string ToString ()
208                 {
209                         return ToString (address);
210                 }
211
212                 /// <summary>
213                 ///   Returns this object rendered in a quad-dotted notation
214                 /// </summary>
215                 static string ToString (long addr)
216                 {
217                         // addr is in network order
218                         return  (addr & 0xff).ToString () + "." +
219                                 ((addr >> 8) & 0xff).ToString () + "." +
220                                 ((addr >> 16) & 0xff).ToString () + "." +
221                                 ((addr >> 24) & 0xff).ToString ();
222                 }
223
224                 /// <returns>
225                 ///   Whether both objects are equal.
226                 /// </returns>
227                 public override bool Equals (object other)
228                 {
229                         if (other is System.Net.IPAddress){
230                                 return Address == ((System.Net.IPAddress) other).Address;
231                         }
232                         return false;
233                 }
234
235                 public override int GetHashCode ()
236                 {
237                         return (int)Address;
238                 }
239         }
240 }