///////////////////////////////////////////////////////
| 225 | |
| 226 | //////////////////////////////////////////////////////////// |
| 227 | std::optional<IpAddress> IpAddress::getLocalAddress(Type type) |
| 228 | { |
| 229 | // The method here is to connect a UDP socket to a public ip, |
| 230 | // and get the local socket address with the getsockname function. |
| 231 | // UDP connection will not send anything to the network, so this function won't cause any overhead. |
| 232 | |
| 233 | if (type == Type::IpV4) |
| 234 | { |
| 235 | // Create the socket |
| 236 | const SocketHandle sock = socket(PF_INET, SOCK_DGRAM, 0); |
| 237 | if (sock == priv::SocketImpl::invalidSocket()) |
| 238 | { |
| 239 | err() << "Failed to retrieve local address (invalid socket)" << std::endl; |
| 240 | return std::nullopt; |
| 241 | } |
| 242 | |
| 243 | // Connect the socket to a public ip (here 1.1.1.1) on any |
| 244 | // port. This will give the local address of the network interface |
| 245 | // used for default routing which is usually what we want. |
| 246 | sockaddr_in address = priv::SocketImpl::createAddress(0x01010101, 9); |
| 247 | if (connect(sock, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == -1) |
| 248 | { |
| 249 | priv::SocketImpl::close(sock); |
| 250 | |
| 251 | err() << "Failed to retrieve local address (socket connection failure)" << std::endl; |
| 252 | return std::nullopt; |
| 253 | } |
| 254 | |
| 255 | // Get the local address of the socket connection |
| 256 | priv::SocketImpl::AddrLength size = sizeof(address); |
| 257 | if (getsockname(sock, reinterpret_cast<sockaddr*>(&address), &size) == -1) |
| 258 | { |
| 259 | priv::SocketImpl::close(sock); |
| 260 | |
| 261 | err() << "Failed to retrieve local address (socket local address retrieval failure)" << std::endl; |
| 262 | return std::nullopt; |
| 263 | } |
| 264 | |
| 265 | // Close the socket |
| 266 | priv::SocketImpl::close(sock); |
| 267 | |
| 268 | // Finally build the IP address |
| 269 | return IpAddress(ntohl(address.sin_addr.s_addr)); |
| 270 | } |
| 271 | |
| 272 | // If we get to this point the user wants to get the local IPv6 address |
| 273 | |
| 274 | // Create the socket |
| 275 | const SocketHandle sock = socket(PF_INET6, SOCK_DGRAM, 0); |
| 276 | if (sock == priv::SocketImpl::invalidSocket()) |
| 277 | { |
| 278 | err() << "Failed to retrieve local address (invalid socket)" << std::endl; |
| 279 | return std::nullopt; |
| 280 | } |
| 281 | |
| 282 | // Connect the socket to a public ip (here 2a00::1) on any |
| 283 | // port. This will give the local address of the network interface |
| 284 | // used for default routing which is usually what we want. |