Reputation: 16409
I want to call the Posix socket functions socket
and bind
from Swift. socket
is pretty easy—it takes Int32
s, but bind
is causing a problem, because I have a sockaddr_in
pointer, but it wants a sockaddr
pointer. In C, this would be a cast, like:
bind(sock, (struct sockaddr *)&sockAddress, sizeof(sockAddress))
Here's an attempt in Swift:
let sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
var sockAddress = sockaddr_in()
bind(sock, &sockAddress, UInt32(MemoryLayout<sockaddr_in>.size))
The bind
line fails to compile with: cannot convert value of type 'sockaddr_in' to expected argument type 'sockaddr'
How do I cast the pointer?
Upvotes: 3
Views: 4243
Reputation: 653
Swift 5 obsolete the withUnsafeBytes(UnsafePointer<sockaddr>)
, so below is what I'm doing with Swift 5:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
return withUnsafeBytes { (p: UnsafeRawBufferPointer) -> String? in
let addr = p.baseAddress?.assumingMemoryBound(to: sockaddr.self)
guard getnameinfo(addr, socklen_t(self.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
return nil
}
return String(cString: hostname)
}
Upvotes: 0
Reputation: 47886
You can write something like this:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
sockaddrInPtr.withMemoryRebound(to: sockaddr.self, capacity: 1) {sockaddrPtr in
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
}
Or someone suggests this may be better:
withUnsafePointer(to: &sockAddress) {sockaddrInPtr in
let sockaddrPtr = UnsafeRawPointer(sockaddrInPtr).assumingMemoryBound(to: sockaddr.self)
bind(sock, sockaddrPtr, UInt32(MemoryLayout<sockaddr_in>.stride))
}
This article may be some help.
(UPDATE)
As described in the link shown by Martin R, now MemoryLayout<T>.stride
and MemoryLayout<T>.size
return the same value which is consistent with C's sizeof
, where T is an imported C-struct. I'll keep my stride
version of answer here, but that is not something "required" in this case now.
Upvotes: 8
Reputation: 539765
In Swift 3 you have to "rebind" the pointer (compare SE-0107 UnsafeRawPointer API):
let sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)
var sockAddress = sockaddr_in()
let result = withUnsafePointer(to: &sockAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(sock, $0, socklen_t(MemoryLayout<sockaddr_in>.stride))
}
}
Remarks:
The type annotations in let sock: Int32
and var sockAddress: sockaddr_in
are not needed.
The memset()
is not necessary because sockaddr_in()
initializes
all struct members to zero.
The Swift equivalent of the C (This "problem" does not exist anymore.
For structs imported from C, sizeof
is stride
(which includes
a possible struct padding), not size
(which does not include the
struct padding).stride
and size
have the same value.)
Upvotes: 4