1 //------------------------------------------------------------------------------
2 // <copyright file="SocketAddress.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
10 using System.Runtime.InteropServices;
11 using System.Net.Sockets;
13 using System.Globalization;
14 using System.Diagnostics.Contracts;
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
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.
28 public class SocketAddress {
30 internal const int IPv6AddressSize = 28;
31 internal const int IPv4AddressSize = 16;
34 internal byte[] m_Buffer;
36 private const int WriteableOffset = 2;
37 private const int MaxSize = 32; // IrDA requires 32 bytes
38 private bool m_changed = true;
45 /// <para>[To be supplied.]</para>
47 public AddressFamily Family {
51 family = ((int)m_Buffer[0]<<8) | m_Buffer[1];
53 family = m_Buffer[0] | ((int)m_Buffer[1]<<8);
55 return (AddressFamily)family;
59 // Size of this SocketAddress
62 /// <para>[To be supplied.]</para>
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
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>
82 /// <para>[To be supplied.]</para>
84 public byte this[int offset] {
89 if (offset<0 || offset>=Size) {
90 throw new IndexOutOfRangeException();
92 return m_Buffer[offset];
95 if (offset<0 || offset>=Size) {
96 throw new IndexOutOfRangeException();
98 if (m_Buffer[offset] != value) {
101 m_Buffer[offset] = value;
106 /// <para>[To be supplied.]</para>
108 public SocketAddress(AddressFamily family) : this(family, MaxSize) {
112 /// <para>[To be supplied.]</para>
114 public SocketAddress(AddressFamily family, int size) {
115 if (size<WriteableOffset) {
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.
120 throw new ArgumentOutOfRangeException("size");
123 m_Buffer = new byte[(size/IntPtr.Size+2)*IntPtr.Size];//sizeof DWORD
126 m_Buffer[0] = unchecked((byte)((int)family>>8));
127 m_Buffer[1] = unchecked((byte)((int)family ));
129 m_Buffer[0] = unchecked((byte)((int)family ));
130 m_Buffer[1] = unchecked((byte)((int)family>>8));
134 internal SocketAddress(IPAddress ipAddress)
135 : this(ipAddress.AddressFamily,
136 ((ipAddress.AddressFamily == AddressFamily.InterNetwork) ? IPv4AddressSize : IPv6AddressSize)) {
139 m_Buffer[2] = (byte)0;
140 m_Buffer[3] = (byte)0;
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;
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);
156 // Address serialization
157 byte[] addressBytes = ipAddress.GetAddressBytes();
158 for (int i = 0; i < addressBytes.Length; i++) {
159 m_Buffer[8 + i] = addressBytes[i];
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));
170 internal SocketAddress(IPAddress ipaddress, int port)
172 m_Buffer[2] = (byte)(port >> 8);
173 m_Buffer[3] = (byte)port;
176 internal IPAddress GetIPAddress() {
177 if (Family == AddressFamily.InterNetworkV6) {
178 Contract.Assert(Size >= IPv6AddressSize);
180 byte[] address = new byte[IPAddress.IPv6AddressBytes];
181 for (int i = 0; i < address.Length; i++) {
182 address[i] = m_Buffer[i + 8];
185 long scope = (long)((m_Buffer[27] << 24) +
186 (m_Buffer[26] << 16) +
187 (m_Buffer[25] << 8) +
190 return new IPAddress(address, scope);
192 } else if (Family == AddressFamily.InterNetwork) {
193 Contract.Assert(Size >= IPv4AddressSize);
195 long address = (long)(
196 (m_Buffer[4] & 0x000000FF) |
197 (m_Buffer[5] << 8 & 0x0000FF00) |
198 (m_Buffer[6] << 16 & 0x00FF0000) |
200 ) & 0x00000000FFFFFFFF;
202 return new IPAddress(address);
205 throw new SocketException(SocketError.AddressFamilyNotSupported);
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);
216 // For ReceiveFrom we need to pin address size, using reserved m_Buffer space
218 internal void CopyAddressSizeIntoBuffer()
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));
226 // Can be called after the above method did work
228 internal int GetAddressSizeOffset()
230 return m_Buffer.Length-IntPtr.Size;
234 // For ReceiveFrom we need to update the address size upon IO return
236 internal unsafe void SetSize(IntPtr ptr)
238 // Apparently it must be less or equal the original value since ReceiveFrom cannot reallocate the address buffer
241 public override bool Equals(object comparand) {
242 SocketAddress castedComparand = comparand as SocketAddress;
243 if (castedComparand == null || this.Size != castedComparand.Size) {
246 for(int i=0; i<this.Size; i++) {
247 if(this[i]!=castedComparand[i]) {
254 public override int GetHashCode() {
260 int size = Size & ~3;
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);
268 if ((Size & 3) != 0) {
273 for (; i < Size; ++i) {
274 remnant |= ((int)m_Buffer[i]) << shift;
283 public override string ToString() {
284 StringBuilder bytes = new StringBuilder();
285 for(int i=WriteableOffset; i<this.Size; i++) {
286 if (i>WriteableOffset) {
289 bytes.Append(this[i].ToString(NumberFormatInfo.InvariantInfo));
291 return Family.ToString() + ":" + Size.ToString(NumberFormatInfo.InvariantInfo) + ":{" + bytes.ToString() + "}";
294 } // class SocketAddress
297 } // namespace System.Net