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