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