context: //
  // System.Net.IPEndPoint.cs
  //
  // Author:
  //   Miguel de Icaza (miguel@ximian.com)
  //
  // (C) Ximian, Inc.  http://www.ximian.com
  //
  
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  using System.Net.Sockets;
  
  namespace System.Net {
  	[Serializable]
  	public class IPEndPoint : EndPoint {
  
  		private IPAddress address;
  		private int port;
  
  		public const int MaxPort = 65535;
  		public const int MinPort = 0;
  		
  		public IPEndPoint (IPAddress address, int port)
  		{
  			if (address == null)
  				throw new ArgumentNullException ("address");
  
  			Address = address;
  			Port = port;
  		}
  		
  		public IPEndPoint (long address, int port)
  		{
  			Address = new IPAddress (address);
  			Port = port;
  		}
  
  		public IPAddress Address {
  			get {
  				return (address);
  			}
  			set {
  				address=value;
  			}
  		}
  
  		public override AddressFamily AddressFamily {
  			get {
  				return address.AddressFamily;
  			}
  		}
  
  		public int Port {
  			get {
  				return port;
  			}
  			set {
  				// LAMESPEC: no mention of sanity checking
  				// PS: MS controls the range when setting the value
  				if (value < MinPort || value > MaxPort)
  					throw new ArgumentOutOfRangeException ("Invalid port");
  			
  				port = value;
  			}
  		}
  
  		// bytes 2 and 3 store the port, the rest
  		// stores the address
  		public override EndPoint Create (SocketAddress socketAddress)
  		{
  			if (socketAddress == null)
  				throw new ArgumentNullException ("socketAddress");
  
  			if (socketAddress.Family != AddressFamily)
  				throw new ArgumentException ("The IPEndPoint was created using " + AddressFamily + 
  						" AddressFamily but SocketAddress contains " + socketAddress.Family + 
  						" instead, please use the same type.");
  
  			SocketAddress sockaddr = socketAddress;
  			int size =sockaddr.Size;
  			AddressFamily family = sockaddr.Family;
  			int port;
  
  			IPEndPoint ipe = null;
  			switch(family)
  			{
  				case AddressFamily.InterNetwork:
  					if (size < 8) {
  						return(null);
  					}
  					
  					port = (((int)sockaddr[2])<<8) + (int)sockaddr[3];
  					long address=(((long)sockaddr[7])<<24) +
  						(((long)sockaddr[6])<<16) +
  						(((long)sockaddr[5])<<8) +
  						(long)sockaddr[4];
  
  					ipe = new IPEndPoint(address, port);
  					break;
  				case AddressFamily.InterNetworkV6:
  					if (size < 28) {
  						return(null);
  					}
  					
  					port	= (((int)sockaddr[2])<<8) + (int)sockaddr[3];
  
  					/// maybe flowid ?
  					/*
  					int unknown	= (int)sockaddr[4] +
  						(((int)sockaddr[5])<<8) +
  						(((int)sockaddr[6])<<16) +
  						(((int)sockaddr[7])<<24);
  					*/
  
  					int scopeId	= (int)sockaddr[24] +
  						(((int)sockaddr[25])<<8) +
  						(((int)sockaddr[26])<<16) +
  						(((int)sockaddr[27])<<24);
  
  					ushort[] addressData = new ushort[8];
  					for(int i=0; i<8; i++)
  						addressData[i] = (ushort)((sockaddr[8+i*2] << 8) + sockaddr[8+i*2+1]);
  
  					ipe = new IPEndPoint (new IPAddress(addressData, scopeId), port);
  					break;
  				default:
  					return null;
  			}
  
  			return(ipe);
  		}
  
  		public override SocketAddress Serialize() {
  			SocketAddress sockaddr = null;
  
  			switch (address.AddressFamily)
  			{
  				case AddressFamily.InterNetwork:
  					// .net produces a 16 byte buffer, even though
  					// only 8 bytes are used. I guess its just a
  					// holdover from struct sockaddr padding.
  					sockaddr = new SocketAddress(AddressFamily.InterNetwork, 16);
  
  					// bytes 2 and 3 store the port, the rest
  					// stores the address
  					sockaddr [2] = (byte) ((port>>8) & 0xff);
  					sockaddr [3] = (byte) (port & 0xff);
  					long addr = address.InternalIPv4Address;
  					sockaddr [4] = (byte) (addr & 0xff);
  					sockaddr [5] = (byte) ((addr >> 8) & 0xff);
  					sockaddr [6] = (byte) ((addr >> 16) & 0xff);
  					sockaddr [7] = (byte) ((addr >> 24) & 0xff);
  					break;
  
  				case AddressFamily.InterNetworkV6:
  					sockaddr = new SocketAddress(AddressFamily.InterNetworkV6, 28);
  
  					sockaddr [2] = (byte) ((port>>8) & 0xff);
  					sockaddr [3] = (byte) (port & 0xff);
  
  					byte[] addressBytes = address.GetAddressBytes();
  					for(int i=0; i<16; i++)
  						sockaddr[8+i] = addressBytes[i];
  					
  					sockaddr [24] = (byte) (address.ScopeId & 0xff);
  					sockaddr [25] = (byte) ((address.ScopeId >> 8) & 0xff);
  					sockaddr [26] = (byte) ((address.ScopeId >> 16) & 0xff);
  					sockaddr [27] = (byte) ((address.ScopeId >> 24) & 0xff);
  					break;
  			}
  
  			return(sockaddr);
  		}
  
  		public override string ToString() {
  			return(address.ToString() + ":" + port);
  		}
  
  		public override bool Equals (object comparand)
  		{
  			IPEndPoint p = comparand as IPEndPoint;
  
gt: 			return p != null && 