Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast sockaddr_in to sockaddr in swift

I'm trying to do some network code in swift and the type checking is giving me fits.

var sock: CInt = ...
var rin: sockaddr_in
var rlen = socklen_t(sizeof(sockaddr_in))
var buffer: CChar[] = CChar[](count: 128, repeatedValue: 0)

let len = recvfrom(sock, &buffer, 128, 0, &rin, &rlen)

The compiler complains (very cryptically) at the recvfrom about the fact that &rin is a pointer to sockaddr_in instead of sockaddr. I tried various ways to convert the pointer type, but I can't seem to get this right.

If I declare it to be a sockaddr I can get this to compile, but then I can't look at it as a sockaddr_in.

like image 922
Matt Avatar asked Jul 24 '14 16:07

Matt


1 Answers

Update for Swift 3 and later, compare UnsafeRawPointer Migration:

var sock: CInt = 1234
var rin = sockaddr_in()
var rlen = socklen_t(MemoryLayout.size(ofValue: rin))
var buffer = [CChar](repeating: 0, count: 128)

let len = withUnsafeMutablePointer(to: &rin) {
    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        recvfrom(sock, &buffer, buffer.count, 0, $0, &rlen)
    }
}

Update: As of Swift 1.2 (Xcode 6.3 beta), initializing a C struct has become much simpler:

var rin = sockaddr_in()

defines a sockaddr_in variable and initializes all elements to zero. The conversion of a address of sockaddr_in to an an address of sockaddr is done as follows:

let len = withUnsafeMutablePointer(&rin) {
    recvfrom(sock, &buffer, UInt(buffer.count), 0, UnsafeMutablePointer($0), &rlen)
}

Old answer: The first problem is that the sockaddr_in variable has to be initialized before its address can be passed to recvfrom(). Initializing complex structs in Swift seems to be clumsy, compare

  • Swift: Pass Uninitialized C Structure to Imported C function.

Using the helper function from https://stackoverflow.com/a/24335355/1187415:

func initStruct<S>() -> S {
    let struct_pointer = UnsafeMutablePointer<S>.alloc(1)
    let struct_memory = struct_pointer.move()
    struct_pointer.dealloc(1)
    return struct_memory
}

the socket address can be initialized as

var rin : sockaddr_in = initStruct()

To cast the sockaddr_in pointer to a sockaddr pointer, use reinterpretCast().

let len = recvfrom(sock, &buffer, UInt(buffer.count), 0, reinterpretCast(&rin), &rlen)
like image 103
Martin R Avatar answered Oct 27 '22 00:10

Martin R