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 <[email protected]> wrote:
>
>>
>> On Sep 12, 2016, at 12:39 PM, Bouke Haarsma via swift-users
>> <[email protected] <mailto:[email protected]>> 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 <[email protected]
>>> <mailto:[email protected]>> 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 <[email protected]
>>>> <mailto:[email protected]>> 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 <[email protected]
>>>>> <mailto:[email protected]>> 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
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-users
>> <https://lists.swift.org/mailman/listinfo/swift-users>
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users