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)")
}
}
}
apple sample code https://developer.apple.com/library/ios/samplecode/SimpleTunnel/Listings/tunnel_server_UDPServerConnection_swift.html
func getEndpointFromSocketAddress(socketAddressPointer: UnsafePointer<sockaddr>) -> (host: String, port: Int)? {
let socketAddress = UnsafePointer<sockaddr>(socketAddressPointer).memory
switch Int32(socketAddress.sa_family) {
case AF_INET:
var socketAddressInet = UnsafePointer<sockaddr_in>(socketAddressPointer).memory
let length = Int(INET_ADDRSTRLEN) + 2
var buffer = [CChar](count: length, repeatedValue: 0)
let hostCString = inet_ntop(AF_INET, &socketAddressInet.sin_addr, &buffer, socklen_t(length))
let port = Int(UInt16(socketAddressInet.sin_port).byteSwapped)
return (String.fromCString(hostCString)!, port)
case AF_INET6:
var socketAddressInet6 = UnsafePointer<sockaddr_in6>(socketAddressPointer).memory
let length = Int(INET6_ADDRSTRLEN) + 2
var buffer = [CChar](count: length, repeatedValue: 0)
let hostCString = inet_ntop(AF_INET6, &socketAddressInet6.sin6_addr, &buffer, socklen_t(length))
let port = Int(UInt16(socketAddressInet6.sin6_port).byteSwapped)
return (String.fromCString(hostCString)!, port)
default:
return nil
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.