Adding reference source for System.Net
[mono.git] / mcs / class / referencesource / System / net / System / Net / SocketAddress.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SocketAddress.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net {
8
9     using System;
10     using System.Runtime.InteropServices;
11     using System.Net.Sockets;
12     using System.Text;
13     using System.Globalization;
14     using System.Diagnostics.Contracts;
15
16     // a little perf app measured these times when comparing the internal
17     // buffer implemented as a managed byte[] or unmanaged memory IntPtr
18     // that's why we use byte[]
19     // byte[] total ms:19656
20     // IntPtr total ms:25671
21
22     /// <devdoc>
23     ///    <para>
24     ///       This class is used when subclassing EndPoint, and provides indication
25     ///       on how to format the memeory buffers that winsock uses for network addresses.
26     ///    </para>
27     /// </devdoc>
28     public class SocketAddress {
29
30         internal const int IPv6AddressSize = 28;
31         internal const int IPv4AddressSize = 16;
32
33         internal int m_Size;
34         internal byte[] m_Buffer;
35
36         private const int WriteableOffset = 2;
37         private const int MaxSize = 32; // IrDA requires 32 bytes
38         private bool m_changed = true;
39         private int m_hash;
40
41         //
42         // Address Family
43         //
44         /// <devdoc>
45         ///    <para>[To be supplied.]</para>
46         /// </devdoc>
47         public AddressFamily Family {
48             get {
49                 int family;
50 #if BIGENDIAN
51                 family = ((int)m_Buffer[0]<<8) | m_Buffer[1];
52 #else
53                 family = m_Buffer[0] | ((int)m_Buffer[1]<<8);
54 #endif
55                 return (AddressFamily)family;
56             }
57         }
58         //
59         // Size of this SocketAddress
60         //
61         /// <devdoc>
62         ///    <para>[To be supplied.]</para>
63         /// </devdoc>
64         public int Size {
65             get {
66                 return m_Size;
67             }
68         }
69
70         //
71         // access to unmanaged serialized data. this doesn't
72         // allow access to the first 2 bytes of unmanaged memory
73         // that are supposed to contain the address family which
74         // is readonly.
75         //
76         // <SECREVIEW> you can still use negative offsets as a back door in case
77         // winsock changes the way it uses SOCKADDR. maybe we want to prohibit it?
78         // maybe we should make the class sealed to avoid potentially dangerous calls
79         // into winsock with unproperly formatted data? </SECREVIEW>
80         //
81         /// <devdoc>
82         ///    <para>[To be supplied.]</para>
83         /// </devdoc>
84         public byte this[int offset] {
85             get {
86                 //
87                 // access
88                 //
89                 if (offset<0 || offset>=Size) {
90                     throw new IndexOutOfRangeException();
91                 }
92                 return m_Buffer[offset];
93             }
94             set {
95                 if (offset<0 || offset>=Size) {
96                     throw new IndexOutOfRangeException();
97                 }
98                 if (m_Buffer[offset] != value) {
99                     m_changed = true;
100                 }
101                 m_Buffer[offset] = value;
102             }
103         }
104
105         /// <devdoc>
106         ///    <para>[To be supplied.]</para>
107         /// </devdoc>
108         public SocketAddress(AddressFamily family) : this(family, MaxSize) {
109         }
110
111         /// <devdoc>
112         ///    <para>[To be supplied.]</para>
113         /// </devdoc>
114         public SocketAddress(AddressFamily family, int size) {
115             if (size<WriteableOffset) {
116                 //
117                 // it doesn't make sense to create a socket address with less tha
118                 // 2 bytes, that's where we store the address family.
119                 //
120                 throw new ArgumentOutOfRangeException("size");
121             }
122             m_Size = size;
123             m_Buffer = new byte[(size/IntPtr.Size+2)*IntPtr.Size];//sizeof DWORD
124
125 #if BIGENDIAN
126             m_Buffer[0] = unchecked((byte)((int)family>>8));
127             m_Buffer[1] = unchecked((byte)((int)family   ));
128 #else
129             m_Buffer[0] = unchecked((byte)((int)family   ));
130             m_Buffer[1] = unchecked((byte)((int)family>>8));
131 #endif
132         }
133         
134         internal SocketAddress(IPAddress ipAddress)
135             : this(ipAddress.AddressFamily, 
136                 ((ipAddress.AddressFamily == AddressFamily.InterNetwork) ? IPv4AddressSize : IPv6AddressSize)) {
137
138             // No Port
139             m_Buffer[2] = (byte)0;
140             m_Buffer[3] = (byte)0;
141
142             if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) {
143                 // No handling for Flow Information
144                 m_Buffer[4] = (byte)0;
145                 m_Buffer[5] = (byte)0;
146                 m_Buffer[6] = (byte)0;
147                 m_Buffer[7] = (byte)0;
148
149                 // Scope serialization
150                 long scope = ipAddress.ScopeId;
151                 m_Buffer[24] = (byte)scope;
152                 m_Buffer[25] = (byte)(scope >> 8);
153                 m_Buffer[26] = (byte)(scope >> 16);
154                 m_Buffer[27] = (byte)(scope >> 24);
155
156                 // Address serialization
157                 byte[] addressBytes = ipAddress.GetAddressBytes();
158                 for (int i = 0; i < addressBytes.Length; i++) {
159                     m_Buffer[8 + i] = addressBytes[i];
160                 }
161             } else {
162                 // IPv4 Address serialization
163                 m_Buffer[4] = unchecked((byte)(ipAddress.m_Address));
164                 m_Buffer[5] = unchecked((byte)(ipAddress.m_Address >> 8));
165                 m_Buffer[6] = unchecked((byte)(ipAddress.m_Address >> 16));
166                 m_Buffer[7] = unchecked((byte)(ipAddress.m_Address >> 24));
167             }
168         }
169
170         internal SocketAddress(IPAddress ipaddress, int port)
171             : this (ipaddress) {
172             m_Buffer[2] = (byte)(port >> 8);
173             m_Buffer[3] = (byte)port;
174         }
175         
176         internal IPAddress GetIPAddress() {
177             if (Family == AddressFamily.InterNetworkV6) {
178                 Contract.Assert(Size >= IPv6AddressSize);
179
180                 byte[] address = new byte[IPAddress.IPv6AddressBytes];
181                 for (int i = 0; i < address.Length; i++) {
182                     address[i] = m_Buffer[i + 8];
183                 }
184
185                 long scope = (long)((m_Buffer[27] << 24) +
186                                     (m_Buffer[26] << 16) +
187                                     (m_Buffer[25] << 8) +
188                                     (m_Buffer[24]));
189
190                 return new IPAddress(address, scope);
191
192             } else if (Family == AddressFamily.InterNetwork) {
193                 Contract.Assert(Size >= IPv4AddressSize);
194
195                 long address = (long)(
196                         (m_Buffer[4] & 0x000000FF) |
197                         (m_Buffer[5] << 8 & 0x0000FF00) |
198                         (m_Buffer[6] << 16 & 0x00FF0000) |
199                         (m_Buffer[7] << 24)
200                         ) & 0x00000000FFFFFFFF;
201
202                 return new IPAddress(address);
203
204             } else {
205                 throw new SocketException(SocketError.AddressFamilyNotSupported);
206             }
207         }
208
209         internal IPEndPoint GetIPEndPoint() {
210             IPAddress address = GetIPAddress();
211             int port = (int)((m_Buffer[2] << 8 & 0xFF00) | (m_Buffer[3]));
212             return new IPEndPoint(address, port);
213         }
214
215         //
216         // For ReceiveFrom we need to pin address size, using reserved m_Buffer space
217         //
218         internal void CopyAddressSizeIntoBuffer()
219         {
220             m_Buffer[m_Buffer.Length-IntPtr.Size]   = unchecked((byte)(m_Size));
221             m_Buffer[m_Buffer.Length-IntPtr.Size+1] = unchecked((byte)(m_Size >> 8));
222             m_Buffer[m_Buffer.Length-IntPtr.Size+2] = unchecked((byte)(m_Size >> 16));
223             m_Buffer[m_Buffer.Length-IntPtr.Size+3] = unchecked((byte)(m_Size >> 24));
224         }
225         //
226         // Can be called after the above method did work
227         //
228         internal int GetAddressSizeOffset()
229         {
230             return m_Buffer.Length-IntPtr.Size;
231         }
232         //
233         //
234         // For ReceiveFrom we need to update the address size upon IO return
235         //
236         internal unsafe void SetSize(IntPtr ptr)
237         {
238             // Apparently it must be less or equal the original value since ReceiveFrom cannot reallocate the address buffer
239             m_Size = *(int*)ptr;
240         }
241         public override bool Equals(object comparand) {
242             SocketAddress castedComparand = comparand as SocketAddress;
243             if (castedComparand == null || this.Size != castedComparand.Size) {
244                 return false;
245             }
246             for(int i=0; i<this.Size; i++) {
247                 if(this[i]!=castedComparand[i]) {
248                     return false;
249                 }
250             }
251             return true;
252         }
253
254         public override int GetHashCode() {
255             if (m_changed) {
256                 m_changed = false;
257                 m_hash = 0;
258
259                 int i;
260                 int size = Size & ~3;
261
262                 for (i = 0; i < size; i += 4) {
263                     m_hash ^= (int)m_Buffer[i]
264                             | ((int)m_Buffer[i+1] << 8)
265                             | ((int)m_Buffer[i+2] << 16)
266                             | ((int)m_Buffer[i+3] << 24);
267                 }
268                 if ((Size & 3) != 0) {
269
270                     int remnant = 0;
271                     int shift = 0;
272
273                     for (; i < Size; ++i) {
274                         remnant |= ((int)m_Buffer[i]) << shift;
275                         shift += 8;
276                     }
277                     m_hash ^= remnant;
278                 }
279             }
280             return m_hash;
281         }
282
283         public override string ToString() {
284             StringBuilder bytes = new StringBuilder();
285             for(int i=WriteableOffset; i<this.Size; i++) {
286                 if (i>WriteableOffset) {
287                     bytes.Append(",");
288                 }
289                 bytes.Append(this[i].ToString(NumberFormatInfo.InvariantInfo));
290             }
291             return Family.ToString() + ":" + Size.ToString(NumberFormatInfo.InvariantInfo) + ":{" + bytes.ToString() + "}";
292         }
293
294     } // class SocketAddress
295
296
297 } // namespace System.Net