1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 * 6 * This software is provided 'as-is', without any express or implied warranty. 7 * In no event will the authors be held liable for any damages arising from the 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 */ 24 25 /** 26 * $(U IpAddress) is a utility class for manipulating network addresses. It 27 * provides a set a implicit constructors and conversion functions to easily 28 * build or transform an IP address from/to various representations. 29 * 30 * 31 * Note that $(U IpAddress) currently doesn't support IPv6 nor other types of 32 * network addresses. 33 * Example: 34 * --- 35 * // an invalid address 36 * IpAddress a0; 37 * 38 * // an invalid address (same as a0) 39 * IpAddress a1 = IpAddress.None; 40 * 41 * // the local host address 42 * IpAddress a2 = IpAddress("127.0.0.1"); 43 * 44 * // the broadcast address 45 * IpAddress a3 = IpAddress.Broadcast; 46 * 47 * // a local address 48 * IpAddress a4 = IpAddress(192, 168, 1, 56); 49 * 50 * // a local address created from a network name 51 * IpAddress a5 = IpAddress("my_computer"); 52 * 53 * // a distant address 54 * IpAddress a6 = IpAddress("89.54.1.169"); 55 * 56 * // a distant address created from a network name 57 * IpAddress a7("www.google.com"); 58 * 59 * // my address on the local network 60 * IpAddress a8 = IpAddress.getLocalAddress(); 61 * 62 * // my address on the internet 63 * IpAddress a9 = IpAddress.getPublicAddress(); 64 * --- 65 */ 66 module dsfml.network.ipaddress; 67 68 public import core.time; 69 70 /** 71 * Encapsulate an IPv4 network address. 72 */ 73 struct IpAddress 74 { 75 package uint m_address; 76 package bool m_valid; 77 78 /** 79 * Construct the address from a string. 80 * 81 * Here address can be either a decimal address (ex: "192.168.1.56") or a 82 * network name (ex: "localhost"). 83 * 84 * Params: 85 * address = IP address or network name. 86 */ 87 this(const(char)[] address) 88 { 89 m_address= htonl(sfIpAddress_integerFromString(address.ptr, address.length)); 90 m_valid = true; 91 } 92 93 /** 94 * Construct the address from 4 bytes. 95 * 96 * Calling `IpAddress(a, b, c, d)` is equivalent to calling 97 * `IpAddress("a.b.c.d")`, but safer as it doesn't have to parse a string to 98 * get the address components. 99 * 100 * Params: 101 * byte0 = First byte of the address. 102 * byte1 = Second byte of the address. 103 * byte2 = Third byte of the address. 104 * byte3 = Fourth byte of the address. 105 */ 106 this(ubyte byte0,ubyte byte1,ubyte byte2,ubyte byte3) 107 { 108 m_address = htonl((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3); 109 m_valid = true; 110 } 111 112 /** 113 * Construct the address from a 32-bits integer. 114 * 115 * This constructor uses the internal representation of the address 116 * directly. It should be used only if you got that representation from 117 * `IpAddress.toInteger()`. 118 * 119 * Params: 120 * address = 4 bytes of the address packed into a 32-bits integer 121 */ 122 this(uint address) 123 { 124 m_address = htonl(address); 125 126 m_valid = true; 127 } 128 129 /** 130 * Get an integer representation of the address. 131 * 132 * The returned number is the internal representation of the address, and 133 * should be used for optimization purposes only (like sending the address 134 * through a socket). The integer produced by this function can then be 135 * converted back to an $(U IpAddress) with the proper constructor. 136 * 137 * Returns: 32-bits unsigned integer representation of the address. 138 */ 139 int toInteger() const 140 { 141 return ntohl(m_address); 142 } 143 144 /** 145 * Get a string representation of the address. 146 * 147 * The returned string is the decimal representation of the IP address 148 * (like "192.168.1.56"), even if it was constructed from a host name. 149 * 150 * This string is built using an internal buffer. If you need to store the 151 * string, make a copy. 152 * 153 * Returns: String representation of the address 154 */ 155 const(char)[] toString() const @nogc @trusted 156 { 157 import core.stdc.stdio: sprintf; 158 159 //internal string buffer to prevent using the GC to build the strings 160 static char[16] m_string; 161 162 ubyte* bytes = cast(ubyte*)&m_address; 163 int length = sprintf(m_string.ptr, "%d.%d.%d.%d", bytes[0], bytes[1], 164 bytes[2], bytes[3]); 165 return m_string[0..length]; 166 } 167 168 /** 169 * Get the computer's local address. 170 * 171 * The local address is the address of the computer from the LAN point of 172 * view, i.e. something like 192.168.1.56. It is meaningful only for 173 * communications over the local network. Unlike `getPublicAddress`, this 174 * function is fast and may be used safely anywhere. 175 * 176 * Returns: Local IP address of the computer. 177 */ 178 static IpAddress getLocalAddress() 179 { 180 IpAddress temp; 181 sfIpAddress_getLocalAddress(&temp); 182 return temp; 183 } 184 185 /** 186 * Get the computer's public address. 187 * 188 * The public address is the address of the computer from the internet point 189 * of view, i.e. something like 89.54.1.169. 190 * 191 * It is necessary for communications over the world wide web. The only way 192 * to get a public address is to ask it to a distant website; as a 193 * consequence, this function depends on both your network connection and 194 * the server, and may be very slow. You should use it as few as possible. 195 * 196 * Because this function depends on the network connection and on a distant 197 * server, you may use a time limit if you don't want your program to be 198 * possibly stuck waiting in case there is a problem; this limit is 199 * deactivated by default. 200 * 201 * Params: 202 * timeout = Maximum time to wait 203 * 204 * Returns: Public IP address of the computer. 205 */ 206 static IpAddress getPublicAddress(Duration timeout = Duration.zero()) 207 { 208 IpAddress temp; 209 sfIpAddress_getPublicAddress(&temp, timeout.total!"usecs"); 210 return temp; 211 } 212 213 /// Value representing an empty/invalid address. 214 static immutable(IpAddress) None; 215 /// Value representing any address (0.0.0.0) 216 static immutable(IpAddress) Any = IpAddress(0,0,0,0); 217 /// The "localhost" address (for connecting a computer to itself locally) 218 static immutable(IpAddress) LocalHost = IpAddress(127,0,0,1); 219 /// The "broadcast" address (for sending UDP messages to everyone on a local network) 220 static immutable(IpAddress) Broadcast = IpAddress(255,255,255,255); 221 } 222 223 224 //these have the same implementation, but use different names for readability 225 private uint htonl(uint host) nothrow @nogc @safe 226 { 227 version(LittleEndian) 228 { 229 import core.bitop; 230 return bswap(host); 231 } 232 else 233 { 234 return host; 235 } 236 } 237 238 private uint ntohl(uint network) nothrow @nogc @safe 239 { 240 version(LittleEndian) 241 { 242 import core.bitop; 243 return bswap(network); 244 } 245 else 246 { 247 return network; 248 } 249 } 250 251 252 unittest 253 { 254 version(DSFML_Unittest_Network) 255 { 256 import std.stdio; 257 258 writeln("Unittest for IpAdress"); 259 260 IpAddress address1; 261 262 assert(address1 == IpAddress.None); 263 assert(IpAddress.LocalHost == IpAddress("127.0.0.1")); 264 assert(IpAddress.LocalHost == IpAddress(127,0,0,1)); 265 assert(IpAddress(127, 0, 0, 1) == IpAddress(IpAddress(127,0,0,1).toInteger())); 266 267 IpAddress googleIP = IpAddress("google.com"); 268 269 writeln("Google's Ip address: ",googleIP); 270 271 writeln("Your local Ip Address: ", IpAddress.getLocalAddress()); 272 273 writeln("Your public Ip Address: ", IpAddress.getPublicAddress()); 274 275 writeln("Full Ip Address: ", IpAddress(111,111,111,111)); 276 277 writeln(); 278 } 279 } 280 281 private extern(C): 282 283 ///Create an address from a string 284 uint sfIpAddress_integerFromString(const(char)* address, size_t addressLength); 285 286 ///Get the computer's local address 287 void sfIpAddress_getLocalAddress(IpAddress* ipAddress); 288 289 ///Get the computer's public address 290 void sfIpAddress_getPublicAddress(IpAddress* ipAddress, long timeout);