字符数组的 RFC 1071 校验和
RFC 1071 checksum for char array
我很难理解 RFC 1071 中的以下校验和算法:
The following "C" code algorithm computes the checksum with an inner
loop that sums 16-bits at a time in a 32-bit accumulator.
in 6
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
checksum = ~sum;
}
我的目标是获取一个字符数组并计算其校验和,但我不确定未定义的变量是什么。 addr
和checksum
and/or的数据类型是什么,如何将char数组转换为校验和过程中可以使用的格式?我知道 count 是存储在 addr 中的字节数。
编辑:到目前为止,我正在考虑将 char 数组转换为整数,然后获取字节数:
int char_int = sscanf(char_array, "%d", &i);
int addr = char_int;
int count = sizeof(char_int);
由于内部循环以 16 位增量处理数据,因此 addr
必须是指向 16 位值的指针,即 uint16_t * addr
.
checksum
是您希望存储最终结果的任何数据类型。如果您正在计算 16 位校验和,它也将是 uint16_t
.
注意 sum
应该是 unsigned long
,而不是 long
。它在实践中有效,因为网络数据包通常不够大,以至于校验和会溢出 long
(数据包必须至少为 32K 字节)。但是,如果您正在编写通用代码,则应该进行防御性编码。
您可以在以下位置找到使用适当的可移植数据类型的实现:
http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
// Initialise the accumulator.
uint32_t acc=0xffff;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Handle any partial block at the end of the data.
if (length&1) {
uint16_t word=0;
memcpy(&word,data+length-1,1);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Return the checksum in network byte order.
return htons(~acc);
}
我很难理解 RFC 1071 中的以下校验和算法:
The following "C" code algorithm computes the checksum with an inner
loop that sums 16-bits at a time in a 32-bit accumulator.
in 6
{
/* Compute Internet Checksum for "count" bytes
* beginning at location "addr".
*/
register long sum = 0;
while( count > 1 ) {
/* This is the inner loop */
sum += * (unsigned short) addr++;
count -= 2;
}
/* Add left-over byte, if any */
if( count > 0 )
sum += * (unsigned char *) addr;
/* Fold 32-bit sum to 16 bits */
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
checksum = ~sum;
}
我的目标是获取一个字符数组并计算其校验和,但我不确定未定义的变量是什么。 addr
和checksum
and/or的数据类型是什么,如何将char数组转换为校验和过程中可以使用的格式?我知道 count 是存储在 addr 中的字节数。
编辑:到目前为止,我正在考虑将 char 数组转换为整数,然后获取字节数:
int char_int = sscanf(char_array, "%d", &i);
int addr = char_int;
int count = sizeof(char_int);
由于内部循环以 16 位增量处理数据,因此 addr
必须是指向 16 位值的指针,即 uint16_t * addr
.
checksum
是您希望存储最终结果的任何数据类型。如果您正在计算 16 位校验和,它也将是 uint16_t
.
注意 sum
应该是 unsigned long
,而不是 long
。它在实践中有效,因为网络数据包通常不够大,以至于校验和会溢出 long
(数据包必须至少为 32K 字节)。但是,如果您正在编写通用代码,则应该进行防御性编码。
您可以在以下位置找到使用适当的可移植数据类型的实现:
http://www.microhowto.info/howto/calculate_an_internet_protocol_checksum_in_c.html
uint16_t ip_checksum(void* vdata,size_t length) {
// Cast the data pointer to one that can be indexed.
char* data=(char*)vdata;
// Initialise the accumulator.
uint32_t acc=0xffff;
// Handle complete 16-bit blocks.
for (size_t i=0;i+1<length;i+=2) {
uint16_t word;
memcpy(&word,data+i,2);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Handle any partial block at the end of the data.
if (length&1) {
uint16_t word=0;
memcpy(&word,data+length-1,1);
acc+=ntohs(word);
if (acc>0xffff) {
acc-=0xffff;
}
}
// Return the checksum in network byte order.
return htons(~acc);
}