How to cast sockadd to sockaddr_in in swift

匿名 (未验证) 提交于 2019-12-03 02:31:01

问题:

var sa_tab:[sockaddr?] = [sockaddr](repeating: sockaddr(), count: Int(RTAX_MAX)) let addr:sockaddr = sa_tab[Int(RTAX_DST)]! let addr_in:sockaddr_in = unsafeBitCast(addr.self, to: UnsafeMutablePointer<sockaddr_in>.self).pointee 

m getting crash in third line, can’t unsafeBitCast between types of different sizes

Here is the complete method.

func ROUNDUP(a:Int) -> Int{     if (a) > 0 {         return (1 + (((a) - 1) | (MemoryLayout<CLong>.size - 1)))     }     else{      return MemoryLayout<CLong>.size     } }  class func defaultGatewayAddress() -> Int{          var addressIntValue:UInt32 = 0         var mib:[Int32] = [CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY]         let l = UnsafeMutablePointer<Int>.allocate(capacity: MemoryLayout<Int>.size)         var buf: UnsafeMutablePointer<CChar>?         var p: UnsafeMutablePointer<CChar>?         var rt: UnsafeMutablePointer<rt_msghdr>?         var sa:UnsafeMutablePointer<sockaddr>?         var sa_tab:[sockaddr?] = [sockaddr](repeating: sockaddr(), count: Int(RTAX_MAX))         var _:Int         var r:Int = -1          if(sysctl(&mib, u_int(mib.count), nil, l, nil, 0) < 0) {             return -1;         }         print(Int8.max)         print(Int8.min)         if(l.pointee > 0) {              buf = UnsafeMutablePointer<CChar>.allocate(capacity: l.pointee)              if(sysctl(&mib, u_int(mib.count), buf, l, nil, 0) < 0) {                 return -1;             }               p = buf             let maxBuf = buf!.advanced(by: l.pointee)              while (p! < maxBuf) {                  rt = p!.withMemoryRebound(to: rt_msghdr.self, capacity: 1, {$0})                 sa = rt!.advanced(by: 1).withMemoryRebound(to: sockaddr.self, capacity: 1, {$0})                  for i in 0..<RTAX_MAX {                     if (rt!.pointee.rtm_addrs & (1 << i)) == 1{                         print("insert \(sa!.pointee) at \(i)")                         sa_tab.insert(sa!.pointee, at: Int(i))                         sa = sa!.advanced(by: ROUNDUP(a: Int(sa!.pointee.sa_len)))                     }                     else{                         sa_tab.insert(nil, at: Int(i))                     }                     if ((rt!.pointee.rtm_addrs & (RTA_DST|RTA_GATEWAY)) ==  (RTA_DST|RTA_GATEWAY)) &&                         (sa_tab[Int(RTAX_DST)]?.sa_family == sa_family_t(AF_INET)) &&                         (sa_tab[Int(RTAX_GATEWAY)]?.sa_family == sa_family_t(AF_INET)){                          var addr:sockaddr = sa_tab[Int(RTAX_DST)]!                          let addr_in:sockaddr_in = withUnsafePointer(to: &addr) {                             $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {                                 $0.pointee                             }                         }                          if addr_in.sin_addr.s_addr == 0 {                             var buffer = [CChar](repeating: CChar(0), count: Int(IFNAMSIZ) + 1)                             let result = if_indextoname(UInt32((rt?.pointee.rtm_index)!), &buffer)                             var char = "en0".cString(using: .utf8)                             #if arch(i386) || arch(x86_64)                                 // This is a Simulator not an idevice                                 char = "en1".cString(using: .utf8)                             #endif                              if(strcmp(result, char) == 0){                                 r = 0                                 var gatewayAddr:sockaddr = sa_tab[Int(RTAX_GATEWAY)]!                                  let gatewayAddr_in:sockaddr_in = withUnsafePointer(to: &gatewayAddr) {                                     $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {                                         $0.pointee                                     }                                 }                                 addressIntValue = gatewayAddr_in.sin_addr.s_addr                             }                         }                       }                 }                  p = p?.advanced(by: Int((rt?.pointee.rtm_msglen)!))              }              buf!.deallocate(capacity: l.pointee)              let gatewayLongAddress:UInt32 = addressIntValue              print("gatewayLongAddress: \(gatewayLongAddress)")              let gatewayIPAddress = String(format:"%d.%d.%d.%d", (gatewayLongAddress & 0xFF),                                           ((gatewayLongAddress >> 8) & 0xFF),                                           ((gatewayLongAddress >> 16) & 0xFF),                                           ((gatewayLongAddress >> 24) & 0xFF))              print("gatewayIPAddress: \(gatewayIPAddress)")          }          return Int(addressIntValue)     } 

回答1:

You have to take the address of addr (which requires addr to be a variable), use withMemoryRebound() to temporarily rebind it to an sockaddr_in pointer, which can then be dereferenced:

var addr: sockaddr = ... let addr_in = withUnsafePointer(to: &addr) {     $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {         $0.pointee     } } 

There are some problems in your defaultGatewayAddress() method:

  • sa = sa!.advanced(by: ROUNDUP(a: Int(sa!.pointee.sa_len))) advances sa by sa_len multiplied with the size of sockaddr, which is not what you intend.
  • The test if ((rt!.pointee.rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) must be done after the for i in 0..<RTAX_MAX loop.
  • With sa_tab.insert(sa!.pointee, at: Int(i)) you insert new elements into the array instead of replacing them.

Note also that

rt = p!.withMemoryRebound(to: rt_msghdr.self, capacity: 1, {$0}) 

might work here, but it generally unsafe: The $0 pointer is only valid for the execution of the closure and must not be passed to the outside.

Here is a working version of your code. It is essentially a translation of How can I determine the default gateway on iPhone? to Swift (which in turn seems it built on https://github.com/getlantern/libnatpmp/blob/master/getgateway.c).

I have also simplified it a bit and modified to avoid all forced unwraps.

func defaultGatewayAddress() -> in_addr? {      var defaultGateway: in_addr?      var mib:[Int32] = [CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY]     var len = 0     if sysctl(&mib, u_int(mib.count), nil, &len, nil, 0) < 0 {         return nil     }     let buffer = UnsafeMutablePointer<CChar>.allocate(capacity: len)     defer {         buffer.deallocate(capacity: len)     }     if sysctl(&mib, u_int(mib.count), buffer, &len, nil, 0) < 0 {         return nil     }      var sa_tab = [UnsafePointer<sockaddr>?](repeating: nil, count: Int(RTAX_MAX))      var ptr = buffer     while ptr < buffer + len {         ptr.withMemoryRebound(to: rt_msghdr.self, capacity: 1) { rt in             var sa = UnsafeMutableRawPointer(rt + 1).assumingMemoryBound(to: sockaddr.self)             for i in 0..<RTAX_MAX {                 if rt.pointee.rtm_addrs & (1 << i) != 0 {                     sa_tab[Int(i)] = UnsafePointer(sa)                     sa = (UnsafeMutableRawPointer(sa) + Int(sa.pointee.sa_len)).assumingMemoryBound(to: sockaddr.self)                 } else {                      sa_tab[Int(i)] =  nil                 }             }              if let dst = sa_tab[Int(RTAX_DST)],                 dst.pointee.sa_family == sa_family_t(AF_INET),                 let gateway = sa_tab[Int(RTAX_GATEWAY)],                 gateway.pointee.sa_family == sa_family_t(AF_INET)             {                 dst.withMemoryRebound(to: sockaddr_in.self, capacity: 1) { addr in                     if addr.pointee.sin_addr.s_addr == 0 {                          var name = [CChar](repeating: CChar(0), count: Int(IFNAMSIZ) + 1)                         if_indextoname(UInt32((rt.pointee.rtm_index)), &name)                         if String(cString: name) == "en0" {                             defaultGateway = gateway.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {                                 $0.pointee.sin_addr                             }                         }                     }                 }              }             ptr += Int(rt.pointee.rtm_msglen)         }     }      return defaultGateway } 


回答2:

Thanks to Martin's answer for this issue, along with that fixed other areas for getting the gateway address as below:

class func defaultGatewayAddress() -> Int{          var addressIntValue:UInt32 = 0         var mib:[Int32] = [CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY]         let l = UnsafeMutablePointer<Int>.allocate(capacity: MemoryLayout<Int>.size)         var buf: UnsafeMutableRawPointer?         var p: UnsafeMutableRawPointer?         var rt: UnsafeMutablePointer<rt_msghdr>?           var sa_tab:[sockaddr?] = [sockaddr](repeating: sockaddr(), count: Int(RTAX_MAX))          let lengthSysctl = Darwin.sysctl(UnsafeMutablePointer<Int32>(mutating: &mib), UInt32(mib.count), nil, l, nil, 0)          if(lengthSysctl < 0) {             return -1;         }         if(l.pointee > 0) {              buf = malloc(l.pointee)              let bufferSysctl = Darwin.sysctl(UnsafeMutablePointer<Int32>(mutating: &mib), UInt32(mib.count), buf, l, nil, 0)              if(bufferSysctl < 0) {                 return -1;             }              p = buf             let maxBuf = buf!.advanced(by: l.pointee)                while (p! < maxBuf) {                  rt = p!.assumingMemoryBound(to: rt_msghdr.self)                  let destBuf = p!.advanced(by: MemoryLayout<rt_msghdr>.size)                 let gatewayBuf = p!.advanced(by: MemoryLayout<rt_msghdr>.size+MemoryLayout<sockaddr>.size*1)                 let netmaskBuf = p!.advanced(by: MemoryLayout<rt_msghdr>.size+MemoryLayout<sockaddr>.size*2)                 let interfaceNameBuf = p!.advanced(by: MemoryLayout<rt_msghdr>.size+MemoryLayout<sockaddr>.size*4)                 let interfaceAddrBuf = p!.advanced(by: MemoryLayout<rt_msghdr>.size+MemoryLayout<sockaddr>.size*5)                   let dest_sa = destBuf.assumingMemoryBound(to: sockaddr.self)                 let gateway_sa = gatewayBuf.assumingMemoryBound(to: sockaddr.self)                 let netmask_sa = netmaskBuf.assumingMemoryBound(to: sockaddr.self)                 let interfaceName_sa = interfaceNameBuf.assumingMemoryBound(to: sockaddr.self)                 let interfaceAddr_sa = interfaceAddrBuf.assumingMemoryBound(to: sockaddr.self)                  let sockAddrs:[Int32:UnsafeMutablePointer<sockaddr>] = [RTAX_DST:dest_sa, RTAX_GATEWAY:gateway_sa, RTAX_NETMASK:netmask_sa, RTAX_IFP:interfaceName_sa, RTAX_IFA:interfaceAddr_sa]                 for (index, pointer) in sockAddrs {                       let bin = (rt!.pointee.rtm_addrs & (1 << index))                     if bin > 0{                         sa_tab.insert(pointer.pointee, at: Int(index))                     }                     else{                         sa_tab.insert(nil, at: Int(index))                     }                 }                   print("RTA_DST -> \((sa_tab[Int(RTAX_DST)]?.sa_family == sa_family_t(AF_INET)))")                 print("RTA_GATEWAY -> \((sa_tab[Int(RTAX_GATEWAY)]?.sa_family == sa_family_t(AF_INET)))")                 print("RTAX_DST -> \(RTAX_DST)")                 print("RTAX_GATEWAY -> \(RTAX_GATEWAY)")                  if ((rt!.pointee.rtm_addrs & (RTA_DST|RTA_GATEWAY)) ==  (RTA_DST|RTA_GATEWAY)) &&                     (sa_tab[Int(RTAX_DST)]?.sa_family == sa_family_t(AF_INET)) &&                     (sa_tab[Int(RTAX_GATEWAY)]?.sa_family == sa_family_t(AF_INET)){                      var addr:sockaddr = sa_tab[Int(RTAX_DST)]!                      let addr_in:sockaddr_in = withUnsafePointer(to: &addr) {                         $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {                             $0.pointee                         }                     }                      if addr_in.sin_addr.s_addr == 0 {                         var buffer = [CChar](repeating: CChar(0), count: Int(IFNAMSIZ) + 1)                         let result = if_indextoname(UInt32((rt?.pointee.rtm_index)!), &buffer)                         var char = "en0".cString(using: .utf8)                         #if arch(i386) || arch(x86_64)                             // This is a Simulator not an idevice                             char = "en0".cString(using: .utf8)                         #endif                          if(strcmp(result, char) == 0){                             var gatewayAddr:sockaddr = sa_tab[Int(RTAX_GATEWAY)]!                              let gatewayAddr_in:sockaddr_in = withUnsafePointer(to: &gatewayAddr) {                                 $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {                                     $0.pointee                                 }                             }                             addressIntValue = gatewayAddr_in.sin_addr.s_addr                         }                     }                    }                  p = p?.advanced(by: Int((rt?.pointee.rtm_msglen)!))              }              //            buf!.deallocate              let gatewayLongAddress:UInt32 = addressIntValue              print("gatewayLongAddress: \(gatewayLongAddress)")              let gatewayIPAddress = String(format:"%d.%d.%d.%d", (gatewayLongAddress & 0xFF),                                           ((gatewayLongAddress >> 8) & 0xFF),                                           ((gatewayLongAddress >> 16) & 0xFF),                                           ((gatewayLongAddress >> 24) & 0xFF))              print("gatewayIPAddress: \(gatewayIPAddress)")          }          return Int(addressIntValue)     } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!