【发布时间】:2011-08-16 03:30:09
【问题描述】:
我正在尝试在 C 中为 SCTP 协议编写一个数据包解码器,并在取消引用指向结构联合的指针(代表 SCTP 块)时遇到了一些问题。
可能不是每个人都熟悉 SCTP(流控制传输协议),所以这里有一些简短的入门知识:
Stream Control Transmission Protocol
SCTP packet structure
RFC 4960
简而言之,在 SCTP 公共标头之后是一系列一个或多个“块”。大多数情况下,每个 SCTP 数据包只有一种块类型,但您可以进行块捆绑,其中某些块类型可以捆绑到一个数据包中。由于这种捆绑,我不能只在我的 SCTP 标头结构中定义一个联合,然后就结束了。
这就是我想要的struct sctp_header:
struct sctp_header {
uint16_t srcport;
uint16_t dstport;
uint32_t vtag;
uint32_t chksum;
uint8_t ctype;
uint8_t cflags;
uint16_t clength;
void *chunks;
};
对于union sctp_chunks(这个问题被截断为两个块类型):
struct sctp_data {
uint32_t tsn;
uint16_t stream_id;
uint16_t stream_seq;
uint32_t pp_id;
void *data;
};
struct sctp_init {
uint32_t initate_tag;
uint32_t a_rwnd;
uint16_t num_out_streams;
uint16_t num_in_streams;
uint32_t tsn;
void *params;
};
union sctp_chunks {
struct sctp_data *data;
struct sctp_init *init;
};
现在,我将 sctp_chunks 覆盖到 sctp_header->chunks 上(一旦我完成了所有其他必要的检查以确保我坐在 SCTP 数据包上)。然后我在 switch 语句中读取sctp_header->ctype,并基于此,我知道我是否可以访问sctp_header->chunks->data->tsn 或sctp_header->chunks->init->initate_tag(在转换为(sctp_chunks *) 之后),等等其他块类型。稍后,我将进行数学运算并检查剩余的块,并将sctp_chunks 联合重新覆盖到剩余的数据上,直到我处理完所有块。目前,我只对第一个块进行操作。
问题是,尝试访问 data->tsn 或 init->initiate_tag(或任何其他联合成员)会导致 SIGSEGV。我手边没有 GDB(我只是正在编码的机器上的用户),所以我很难弄清楚为什么我的程序会出现段错误。我相信我对结构/联合的使用是合理的,但这就是 C 的本质,它可能是非常微妙的东西让我着迷。
打印chunks->data 或chunks->init 的指针地址显示的地址似乎不是NULL 指针,而且我没有从gcc 中得到任何重大错误或警告,所以我有点难过。
有什么不寻常的地方,还是有更好的方法来解决这个问题?
【问题讨论】:
-
您可以打印简短的内存转储,而不仅仅是指针值,并检查内容是否有意义。结构是否正确对齐(#pragma pack 等)?
-
如果没有
gdb,那就用肮脏的方式,即很多printfs。 -
@Eugene:没有尝试过#pragma pack,但我做了一些修改(将块类型、长度、标志移动到 sctp_chunks 中),一旦我停止让它们成为指针,就可以取消引用这些成员。但是现在我偏移了四个字节,这是奇怪。