Hungry Mind , Blog about everything in IT - C#, Java, C++, .NET, Windows, WinAPI, ...

How to compute IP and TCP checksum

Whenever I need to code something, the very first thing I do is google for a ready to use solution. Some time ago I had to calculate IP and TCP checksums. Every peace of code I googled was unreadable junk. I wonder is it really hard to write good looking readable code, so you can just copy and paste it?!

#pragma pack(push, 1)
 
struct IPV4_HDR
{
    uint8_t ihl : 4;
    uint8_t version : 4;
    uint8_t tos;
    uint16_t total_length;
    uint16_t identification;
 
    uint16_t fragment_offset : 13;
 
    uint16_t more_fragment : 1;
    uint16_t dont_fragment : 1;
    uint16_t reserved_zero : 1;
 
    uint8_t ttl;
    uint8_t proto;
    uint16_t header_checksum;
    uint32_t src_ip;
    uint32_t dst_ip;
};
 
struct TCP_HDR
{
    uint16_t src_port;
    uint16_t dst_port;
    uint32_t seqn;
    uint32_t ackn;
 
    uint8_t ns : 1;
    uint8_t reserved : 3;
    uint8_t data_offset : 4;
 
    uint8_t fin : 1;
    uint8_t syn : 1;
    uint8_t rst : 1;
    uint8_t psh : 1;
    uint8_t ack : 1;
    uint8_t urg : 1;
 
    uint8_t ecn : 1;
    uint8_t cwr : 1;
 
    uint16_t window;
    uint16_t checksum;
    uint16_t urgent_pointer;
};
 
#pragma pack(pop)
 
uint16_t compute_checksum(uint16_t const *data, size_t count)
{
    uint32_t sum = 0;
    while (count > 1) {
        sum += *data++;
        count -= sizeof(uint16_t);
    }
    if (count > 0) sum += ((*data) & htons(0xFF00));
    while (sum >> 16) sum = (sum & 0xFFFF) + (sum >> 16);
    sum = ~sum;
    return static_cast<uint16_t>(sum);
}
 
uint16_t compute_ip_checksum(IPV4_HDR *ip)
{
    ip->header_checksum = 0U;
    return (ip->header_checksum = compute_checksum(reinterpret_cast<uint16_t const *>(ip), ip->ihl << 2));
}
 
uint16_t compute_tcp_checksum(IPV4_HDR const *ip, uint16_t *payload)
{
    uint32_t sum = 0;
    uint16_t tcp_len = ntohs(ip->total_length) - (ip->ihl << 2);
    auto const tcp = reinterpret_cast<TCP_HDR *>(payload);
    sum += (ip->src_ip >> 16) & 0xFFFF;
    sum += (ip->src_ip) & 0xFFFF;
    sum += (ip->dst_ip >> 16) & 0xFFFF;
    sum += (ip->dst_ip) & 0xFFFF;
    sum += htons(IPPROTO_TCP);
    sum += htons(tcp_len);
 
    tcp->checksum = 0;
    while (tcp_len > 1) {
        sum += *payload++;
        tcp_len -= sizeof(uint16_t);
    }
    if (tcp_len > 0) sum += ((*payload) & htons(0xFF00));
    while (sum >> 16) sum = (sum & 0xffff) + (sum >> 16);
    sum = ~sum;
    return (tcp->checksum = static_cast<uint16_t>(sum));
}

__await is still broken in Visual Studio 2015 RTM

Connect issue

The following simple code does not work:

#include "stdafx.h"
#include <experimental\generator>
#include <future>

using namespace std;
using namespace std::experimental;

future<int> get_int()
{
    return async([] { return 0; });
}

future<int> wait_int()
{
    return __await get_int();
}


int main()
{
    auto const i = wait_int().get();
    return 0;
}

App hits int 3 instruction (XXX.exe has triggered a breakpoint) and then hangs forever waiting for suspended coroutine to finish. Bravo! My investigation shows that compiler generates invalid instructions within XXX.exe!wait_int$_ResumeCoro$2() function:

00007FF6166FB0F0  mov         qword ptr [rsp+8],rcx  
00007FF6166FB0F5  push        rbp  
00007FF6166FB0F6  sub         rsp,30h  
00007FF6166FB0FA  mov         qword ptr [rsp+20h],0FFFFFFFFFFFFFFFEh  
00007FF6166FB103  mov         rbp,qword ptr [$S2]  
00007FF6166FB108  mov         eax,dword ptr [rbp+20h]  
00007FF6166FB10B  mov         dword ptr [rbp+78h],eax  
00007FF6166FB10E  cmp         dword ptr [rbp+78h],5  

rbp has the address of coroutine frame, frame has two consequent 64-bit values - address of resume method and some internal state flag, which is set to 2 initially. dword ptr [rbp+20h] - this instruction obtains the flag, but the offset is completely wrong, it must be dword ptr [rbp+8h]. So all cases of state flag switch are bypassed. Default case makes the assert hit. Boom.

UPD: It doesn't support Debug Information Format == Program Database for Edit And Continue (/Zl). With this setting set to something else the code is generated properly: mov eax, [rbp+8].

Lindemann

Он бесподобен, я хочу от него детей!!!!!!11

Establishing an RDP connection with a Windows 8.1 client from Mac OS X

std::numeric_limits<UnsignedIntegral>::max() alternative

std::numeric_limits<uint32_t>::max() == static_cast<uint32_t>(-1) == ~0U

Copyright 2007-2011 Chabster