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