Answering to Is there an alternative way to getifaddrs() for getting the ip-address?
Yes, there is an alternative way. You can also get the ip address by utilizing ioctl(). The cleanest way would be doing it in C and then wrapping it up in Swift. So consider this:
Create a C Source File (Xcode should create it together with a .h) and remember adding the header into your project's bridging header, or into umbrella-header if you have a cocoa touch framework.
Add the following into your .c source and method's declaration into .h:
#include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netinet/in.h> #include <net/if.h> int _interfaceAddressForName(char* interfaceName, struct sockaddr* interfaceAddress) { struct ifreq ifr; int fd = socket(AF_INET, SOCK_DGRAM, 0); ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, interfaceName, IFNAMSIZ-1); int ioctl_res; if ( (ioctl_res = ioctl(fd, SIOCGIFADDR, &ifr)) < 0){ return ioctl_res; } close(fd); memcpy(interfaceAddress, &ifr.ifr_addr, sizeof(struct sockaddr)); return 0; }
Your Swift wrapper might look something like:
public enum Error:ErrorType { case IOCTLFailed(Int32) case StringIsNotAnASCIIString } public func interfaceAddress(forInterfaceWithName interfaceName: String) throws -> sockaddr_in { guard let cString = interfaceName.cStringUsingEncoding(NSASCIIStringEncoding) else { throw Error.StringIsNotAnASCIIString } let addressPtr = UnsafeMutablePointer<sockaddr>.alloc(1) let ioctl_res = _interfaceAddressForName(strdup(cString), addressPtr) let address = addressPtr.move() addressPtr.dealloc(1) if ioctl_res < 0 { throw Error.IOCTLFailed(errno) } else { return unsafeBitCast(address, sockaddr_in.self) } }
Then you can use it in your code like:
let interfaceName = "en0" do { let wlanInterfaceAddress = try interfaceAddress(forInterfaceWithName: interfaceName) print(String.fromCString(inet_ntoa(wlanInterfaceAddress.sin_addr))!) } catch { if case Error.IOCTLFailed(let errno) = error where errno == ENXIO { print("interface(\(interfaceName)) is not available") } else { print(error) } }
en0 typically is the interface you need, which stands for WLAN
If you also need to know available interface names you can utilize if_indextoname():
public func interfaceNames() -> [String] { let MAX_INTERFACES = 128; var interfaceNames = [String]() let interfaceNamePtr = UnsafeMutablePointer<Int8>.alloc(Int(IF_NAMESIZE)) for interfaceIndex in 1...MAX_INTERFACES { if (if_indextoname(UInt32(interfaceIndex), interfaceNamePtr) != nil){ if let interfaceName = String.fromCString(interfaceNamePtr) { interfaceNames.append(interfaceName) } } else { break } } interfaceNamePtr.dealloc(Int(IF_NAMESIZE)) return interfaceNames }
getifaddrs()however seems to be invisible to Swift, perhaps the used data structures are incompatible.