I'm trying to obtain the remote ip address using getpeername()
under iOS/Swift (real hardware no emulation).
This is what I'm doing:
var addr = sockaddr(sa_len: 0, sa_family: 0, sa_data: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
var len: socklen_t = socklen_t(sizeof(Int32))
if getpeername(socket, &addr, &len) != -1
{
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr,
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
println("socket \(socket) ip \(String.fromCString(ipAddressString))")
}
the values that I'm getting are:
socket 7 ip Optional("16.2.209.237")
and that is certainly not the remote address. Please can someone help me? What I'm doing wrong?
The main error is that inet_ntop()
takes the address of a struct in_addr
(or struct in_addr6
for IPv6), and not the address of a struct sockaddr
.
Another error is that the length argument to getpeername()
must be the length of
the passed socket address structure, you are passing the length of an Int32
.
Your current code passes AF_INET
to inet_ntop()
and is therefore limited
to IPv4 addresses. If that is sufficient for you, the following should work:
var addr = UnsafeMutablePointer<sockaddr_in>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))
if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr.memory.sin_addr, // <-- main difference here
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
println("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
addr.dealloc(1)
Allocating the socket address structure makes casting between the different pointer
types a bit easier. I have also replaced the variable name socket
by sockfd
to
avoid confusion with the socket()
function.
The more "modern" function to convert socket addresses to strings is
getnameinfo()
. The following code demonstrates how to use it. It works for
both IPv4 and IPv6 addresses:
var addr = UnsafeMutablePointer<sockaddr_storage>.alloc(1)
var len = socklen_t(sizeofValue(addr.memory))
if getpeername(sockfd, UnsafeMutablePointer(addr), &len) != -1 {
var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(UnsafeMutablePointer(addr), socklen_t(addr.memory.ss_len),
&hostBuffer, socklen_t(hostBuffer.count), nil, 0,
NI_NUMERICHOST) == 0) {
let host = String.fromCString(hostBuffer)!
println("socket \(sockfd) ip \(host)")
}
}
addr.dealloc(1)
Swift 2 update: First method:
var addr = sockaddr_in()
var len = socklen_t(sizeofValue(addr))
withUnsafeMutablePointer(&addr) {
if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
var ipAddressString = [CChar](count:Int(INET_ADDRSTRLEN), repeatedValue: 0)
inet_ntop(
AF_INET ,
&addr.sin_addr, // <-- main difference here
&ipAddressString,
socklen_t(INET_ADDRSTRLEN))
print("socket \(sockfd) ip \(String.fromCString(ipAddressString)!)")
}
}
Second method:
var addr = sockaddr_storage()
var len = socklen_t(sizeofValue(addr))
withUnsafeMutablePointer(&addr) {
if getpeername(sockfd, UnsafeMutablePointer($0), &len) != -1 {
var hostBuffer = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(UnsafeMutablePointer($0), socklen_t(addr.ss_len),
&hostBuffer, socklen_t(hostBuffer.count), nil, 0,
NI_NUMERICHOST) == 0) {
let host = String.fromCString(hostBuffer)!
print("socket \(sockfd) ip \(host)")
}
}
}