sockets swift3 casting

sockets - Cómo lanzar sockadd a sockaddr_in en swift



swift3 casting (2)

Gracias a la respuesta de Martin para este problema, junto con las otras áreas fijadas para obtener la dirección de la puerta de enlace como a continuación:

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) }

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 que se cuelga en la tercera línea, no se puede inseguroBitCast entre tipos de diferentes tamaños

Aquí está el método completo.

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) }


withMemoryRebound() tomar la dirección de addr (que requiere que addr sea ​​una variable ), use withMemoryRebound() para volver a vincularla temporalmente a un puntero sockaddr_in , que luego se puede desreferenciar:

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

Hay algunos problemas en su método defaultGatewayAddress() :

  • sa = sa!.advanced(by: ROUNDUP(a: Int(sa!.pointee.sa_len))) avanza sa por sa_len multiplicado por el tamaño de sockaddr , que no es lo que pretendes.
  • La prueba if ((rt!.pointee.rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) debe realizar después del ciclo for i in 0..<RTAX_MAX .
  • Con sa_tab.insert(sa!.pointee, at: Int(i)) inserta nuevos elementos en la matriz en lugar de reemplazarlos.

Tenga en cuenta también que

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

podría funcionar aquí, pero generalmente no es seguro: el puntero de $0 solo es válido para la ejecución del cierre y no debe pasarse al exterior.

Aquí hay una versión de trabajo de tu código. Es esencialmente una traducción de ¿Cómo puedo determinar la puerta de enlace predeterminada en iPhone? Swift (que a su vez parece estar construido en https://github.com/getlantern/libnatpmp/blob/master/getgateway.c ).

También lo he simplificado un poco y modificado para evitar todos los desempaquetes forzados.

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 }