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