我很难理解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;
}
我的目标是获取一个char数组并计算其校验和,但我不确定未定义的变量是什么。什么是addr
和checksum
的数据类型和/或,我怎么能将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);
}