Thanks for your replies. After looking at the helper code you mentioned, it 
appears that the code in each call will create a mutable copy of a 
sockaddr_storage. That mutable copy is than rebound/casted to whatever type 
requested. While it probably would be safer to use, it introduces extra copying 
overhead as well. The code that I have now (thanks to Quinn’s helper methods):

let address: sockaddr_storage
let family = CFDataGetBytePtr(addressData!).withMemoryRebound(to: 
sockaddr.self, capacity: 1) {
    return $0.pointee.sa_family
}
switch family {
case sa_family_t(AF_INET):
    (_, address) = sockaddr_storage.fromSockAddr { (sin: inout sockaddr_in) in
        sin.sin_family = sa_family_t(AF_INET)
        sin.sin_addr = CFDataGetBytePtr(addressData!).withMemoryRebound(to: 
sockaddr_in.self, capacity: 1) {
            $0.pointee.sin_addr
        }
    }
case sa_family_t(AF_INET6):
    (_, address) = sockaddr_storage.fromSockAddr { (sin: inout sockaddr_in6) in
        sin.sin6_family = sa_family_t(AF_INET6)
        sin.sin6_addr = CFDataGetBytePtr(addressData!).withMemoryRebound(to: 
sockaddr_in6.self, capacity: 1) {
            $0.pointee.sin6_addr
        }
    }
default:
    return
}

Is this as Swifty as it can get? Is there a way to make it less verbose? The 
problem I see with this code is that the network protocols are still 
special-cased. 

The addressData CFData object is described like this:

> A CFData object holding the contents of a struct sockaddr appropriate for the 
> protocol family of s (struct sockaddr_in or struct sockaddr_in6, for 
> example), identifying the remote address to which s is connected. This value 
> is NULL except for kCFSocketAcceptCallBack and kCFSocketDataCallBack 
> callbacks.


Thanks,
Bouke


> On 14 sep. 2016, at 08:34, Andrew Trick <atr...@apple.com> wrote:
> 
>> 
>> On Sep 12, 2016, at 12:39 PM, Bouke Haarsma via swift-users 
>> <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:
>> 
>> Sorry for all the pings, but it appears that the code below doesn’t work 
>> after all;
>> 
>>> fatal error: can't unsafeBitCast between types of different sizes
>> 
>> So the question remains on how to perform the casts using Swift?
>> 
>> —
>> Bouke
> 
> Hi Bouke,
> 
> Please see this migration guide:
> https://swift.org/migration-guide/se-0107-migrate.html 
> <https://swift.org/migration-guide/se-0107-migrate.html>
> 
> It explains a few things that are not self-explanatory and includes some 
> helper code for dealing with the socket API.
> 
> Given how your code is structured, I would start with a raw pointer, then 
> replace all the ‘withMemoryRebound’ calls to ‘bindMemory’, and you should be 
> fine:
> 
> var rawSockAddr = UnsafeRawPointer(CFDataGetBytePtr(data))
> 
> switch …
> case …:
>   let ipv4 = rawSockAddr.bindMemory(to: sockaddr_in.self, capacity: 1)
> 
> You might also be able to avoid CFData and use Swift’s Data directly, but any 
> Swifty API you use will encourage you to restructure your code so that 
> pointer access is confined to a closure, like Data.withUnsafeBytes, or 
> UnsafePointer.withMemoryRebound(to:capacity:). You should never return the 
> pointer argument from these closure. The closure taking APIs are designed to 
> keep your data alive while you access it and make sure you’re not mixing 
> pointers of different types to the same memory.
> 
> -Andy
> 
>>> On 12 sep. 2016, at 21:37, Bouke Haarsma <bo...@haarsma.eu 
>>> <mailto:bo...@haarsma.eu>> wrote:
>>> 
>>> 
>>> Sorry, missed the first line when copying:
>>> 
>>> let generic = unsafeBitCast(CFDataGetBytePtr(data), to: sockaddr.self)
>>> switch generic.sa_family {
>>> case sa_family_t(AF_INET):
>>>     let ipv4 = unsafeBitCast(generic, to: sockaddr_in.self)
>>>     //...
>>> case sa_family_t(AF_INET6):
>>>     let ipv6 = unsafeBitCast(generic, to: sockaddr_in6.self)
>>>     //...
>>> default:
>>>     //...
>>> }
>>> 
>>> —
>>> Bouke
>>> 
>>>> On 12 sep. 2016, at 21:35, Bouke Haarsma <bo...@haarsma.eu 
>>>> <mailto:bo...@haarsma.eu>> wrote:
>>>> 
>>>> Ah the missing part of the puzzle appears to be unsafeBitCast(:to:), so 
>>>> the Swift version becomes this:
>>>> 
>>>> switch generic.sa_family {
>>>> case sa_family_t(AF_INET):
>>>>     let ipv4 = unsafeBitCast(generic, to: sockaddr_in.self)
>>>>     //...
>>>> case sa_family_t(AF_INET6):
>>>>     let ipv6 = unsafeBitCast(generic, to: sockaddr_in6.self)
>>>>     //...
>>>> default:
>>>>     //...
>>>> }
>>>> 
>>>> —
>>>> Bouke
>>>> 
>>>>> On 12 sep. 2016, at 21:25, Bouke Haarsma <bo...@haarsma.eu 
>>>>> <mailto:bo...@haarsma.eu>> wrote:
>>>>> 
>>>>> Hi all,
>>>>> 
>>>>> Inside my CFSocketCallBack a pointer to a sockaddr is provided wrapped in 
>>>>> a CFData structure. The sockaddr could be either a sockaddr_in (IPv4) or 
>>>>> sockaddr_in6 (IPv6) struct. In order to discover which struct you’re 
>>>>> dealing with, the attribute sa_family can be inspected. In C this would 
>>>>> look something like this:
>>>>> 
>>>>> struct sockaddr_storage sa;
>>>>> 
>>>>> switch (((sockaddr*)&sa)->sa_family)
>>>>> {
>>>>>     case AF_INET:
>>>>>         inet_ntop(AF_INET, &(((sockaddr_in*)&sa)->sin_addr), ...);
>>>>>         break;
>>>>>     case AF_INET6:
>>>>>         inet_ntop(AF_INET6, &(((sockaddr_in6*)&sa)->sin6_addr), ...);
>>>>>         break;
>>>>> }
>>>>> (from: http://stackoverflow.com/a/13167913 
>>>>> <http://stackoverflow.com/a/13167913>)
>>>>> 
>>>>> Wheras to do this in Swift 3, the only way I found thus far is this:
>>>>> 
>>>>> var generic = CFDataGetBytePtr(data).withMemoryRebound(to: sockaddr.self, 
>>>>> capacity: 1) {
>>>>>     return $0.pointee
>>>>> }
>>>>> switch generic.sa_family {
>>>>> case sa_family_t(AF_INET):
>>>>>     let ipv4 = withUnsafePointer(to: &generic) {
>>>>>         $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {
>>>>>             $0.pointee
>>>>>         }
>>>>>     }
>>>>>     //...
>>>>> case sa_family_t(AF_INET6):
>>>>>     let ipv6 = withUnsafePointer(to: &generic) {
>>>>>         $0.withMemoryRebound(to: sockaddr_in6.self, capacity: 1) {
>>>>>             $0.pointee
>>>>>         }
>>>>>     }
>>>>>     //...
>>>>> default:
>>>>>     //…
>>>>> }
>>>>> 
>>>>> This looks very ugly with all the closures and ``withMemoryRebound``. Is 
>>>>> there a better way to do this? I think there should be something more 
>>>>> “Swifty”.
>>>>> 
>>>>> —
>>>>> Bouke
>>>> 
>>> 
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org <mailto:swift-users@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-users 
>> <https://lists.swift.org/mailman/listinfo/swift-users>
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to