Контрольная сумма RFC 1071 для массива символов - PullRequest
0 голосов
/ 21 февраля 2019

Мне трудно понять следующий алгоритм контрольной суммы из 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 и / или как я могу преобразовать массив символов в формат, который можно использовать в процессе суммирования чеков?Я знаю, что count - это количество байтов во всем, что хранится в addr.

Редактировать: До сих пор я думаю преобразовать массив char в целое число, а затем получить количество байтов:

int char_int = sscanf(char_array, "%d", &i);
int addr = char_int;
int count = sizeof(char_int);

1 Ответ

0 голосов
/ 21 февраля 2019

Поскольку внутренний цикл обрабатывает данные с 16-битным шагом, addr должен быть указателем на 16-битное значение, т. Е. uint16_t * addr.

checksum - любой тип данных, который вы хотитедля сохранения окончательного результата. Если вы вычисляете 16-битную контрольную сумму, она также будет uint16_t.

. Обратите внимание, что sum, вероятно, должно быть unsigned long, а не long.Это работает на практике, потому что сетевые пакеты, как правило, недостаточно велики, чтобы контрольная сумма переполняла long (пакет должен быть не менее 32 Кбайт).Но если вы пишете код общего назначения, вам следует защищаться от кода.

Вы можете найти реализацию, которая использует подходящие переносимые типы данных:

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