I have the following code to get information about the tcp ports:
我有以下代码来获取有关tcp端口的信息:
var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0)
{
perror("sysctlbyname")
}
else
{
var buffer: [UInt8] = [UInt8](repeating: 0, count: Int(length))
sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0)
}
I now want to convert the buffer into something more "useful". I read that the return value is a struct called "xinpgen". How can I convert the buffer into that struct?
我现在想将缓冲区转换为更“有用”的东西。我读到返回值是一个名为“xinpgen”的结构。如何将缓冲区转换为该结构?
I tried the following code to directly write the result into the struct variable:
我尝试了以下代码直接将结果写入struct变量:
var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0)
{
perror("sysctlbyname")
}
else
{
var input = xinpgen()
sysctlbyname("net.inet.tcp.pcblist", &input, &length, nil, 0)
}
The call itself doesn't fail and seems to be successful. The variable contains some data that isn't zero. But shortly after the call is finished and the program continues, the app crashes:
呼叫本身并没有失败,似乎是成功的。该变量包含一些非零的数据。但是在通话完成并且程序继续之后不久,应用程序崩溃了:
error: memory read failed for 0x0
How can I use the buffer to fill the struct variable? And why does the second call fail?
如何使用缓冲区填充struct变量?为什么第二次通话失败?
1 个解决方案
#1
1
The data returned by sysctlbyname("net.inet.tcp.pcblist", ...)
is not a single xinpgen
structure, but a "packed list" of structures.
sysctlbyname(“net.inet.tcp.pcblist”,...)返回的数据不是单个xinpgen结构,而是结构的“打包列表”。
Your code writes more bytes to the memory address of the input
variable than its size, the behaviour is undefined and a crash very likely.
您的代码将更多字节写入输入变量的内存地址而不是其大小,行为未定义且很可能发生崩溃。
I don't know if the structure of the returned data is documented, but the source code of inet.c shows how it can be parsed. Apparently the buffer starts with a struct xinpgen
, followed by a variable number of struct xtcpcb
, and each element has a length field which contains the offset to the next structure.
我不知道是否记录了返回数据的结构,但inet.c的源代码显示了如何解析它。显然,缓冲区以struct xinpgen开头,后跟可变数量的struct xtcpcb,每个元素都有一个length字段,其中包含到下一个结构的偏移量。
This is my attempt to translate the C code from the above source file to Swift:
这是我尝试将C代码从上面的源文件转换为Swift:
var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0) {
fatalError("sysctlbyname")
}
var buffer = [UInt8](repeating: 0, count: Int(length))
sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0)
buffer.withUnsafeBytes { bufPtr in
// Pointer to first xinpgen structure:
var p = bufPtr.baseAddress!
var xig = p.bindMemory(to: xinpgen.self, capacity: 1)
// Skip first xinpgen structure:
p += Int(xig.pointee.xig_len)
xig = p.bindMemory(to: xinpgen.self, capacity: 1)
while Int(xig.pointee.xig_len) > MemoryLayout<xinpgen>.size {
// Cast xig to xtcpcb pointer and derefernce:
let tcpcb = xig.withMemoryRebound(to: xtcpcb.self, capacity: 1) {
$0.pointee
}
print(tcpcb)
// Advance pointer to next structure
p += Int(xig.pointee.xig_len)
xig = p.bindMemory(to: xinpgen.self, capacity: 1)
}
}
#1
1
The data returned by sysctlbyname("net.inet.tcp.pcblist", ...)
is not a single xinpgen
structure, but a "packed list" of structures.
sysctlbyname(“net.inet.tcp.pcblist”,...)返回的数据不是单个xinpgen结构,而是结构的“打包列表”。
Your code writes more bytes to the memory address of the input
variable than its size, the behaviour is undefined and a crash very likely.
您的代码将更多字节写入输入变量的内存地址而不是其大小,行为未定义且很可能发生崩溃。
I don't know if the structure of the returned data is documented, but the source code of inet.c shows how it can be parsed. Apparently the buffer starts with a struct xinpgen
, followed by a variable number of struct xtcpcb
, and each element has a length field which contains the offset to the next structure.
我不知道是否记录了返回数据的结构,但inet.c的源代码显示了如何解析它。显然,缓冲区以struct xinpgen开头,后跟可变数量的struct xtcpcb,每个元素都有一个length字段,其中包含到下一个结构的偏移量。
This is my attempt to translate the C code from the above source file to Swift:
这是我尝试将C代码从上面的源文件转换为Swift:
var length = 0
if (sysctlbyname("net.inet.tcp.pcblist", nil, &length, nil, 0) < 0) {
fatalError("sysctlbyname")
}
var buffer = [UInt8](repeating: 0, count: Int(length))
sysctlbyname("net.inet.tcp.pcblist", &buffer, &length, nil, 0)
buffer.withUnsafeBytes { bufPtr in
// Pointer to first xinpgen structure:
var p = bufPtr.baseAddress!
var xig = p.bindMemory(to: xinpgen.self, capacity: 1)
// Skip first xinpgen structure:
p += Int(xig.pointee.xig_len)
xig = p.bindMemory(to: xinpgen.self, capacity: 1)
while Int(xig.pointee.xig_len) > MemoryLayout<xinpgen>.size {
// Cast xig to xtcpcb pointer and derefernce:
let tcpcb = xig.withMemoryRebound(to: xtcpcb.self, capacity: 1) {
$0.pointee
}
print(tcpcb)
// Advance pointer to next structure
p += Int(xig.pointee.xig_len)
xig = p.bindMemory(to: xinpgen.self, capacity: 1)
}
}