summaryrefslogtreecommitdiffstats
path: root/src/detection/netio/netio.c
blob: c6b9da61b2b3da8fc39d3238fcc161492ba15e5a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "netio.h"

#include "common/time.h"

static FFlist ioCounters1;
static uint64_t time1;

void ffPrepareNetIO(FFNetIOOptions* options) {
    if (options->detectTotal) {
        return;
    }

    if (time1 != 0) {
        return; // Already prepared
    }

    ffListInit(&ioCounters1);
    ffNetIOGetIoCounters(&ioCounters1, options);
    time1 = ffTimeGetNow();
}

const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options) {
    const char* error = NULL;

    if (options->detectTotal) {
        error = ffNetIOGetIoCounters(result, options);
        if (error) {
            return error;
        }
        return NULL;
    }

    if (time1 == 0) {
        ffListInit(&ioCounters1);
        error = ffNetIOGetIoCounters(&ioCounters1, options);
        if (error) {
            return error;
        }
        time1 = ffTimeGetNow();
    }

    if (ioCounters1.length == 0) {
        return "No network interfaces found";
    }

    uint64_t time2 = ffTimeGetNow();
    while (time2 - time1 < options->waitTime) {
        ffTimeSleep((uint32_t) (options->waitTime - (time2 - time1)));
        time2 = ffTimeGetNow();
    }

    error = ffNetIOGetIoCounters(result, options);
    if (error) {
        return error;
    }

    if (result->length != ioCounters1.length) {
        return "Different number of network interfaces. Network change?";
    }

    for (uint32_t i = 0; i < result->length; ++i) {
        FFNetIOResult* icPrev = FF_LIST_GET(FFNetIOResult, ioCounters1, i);
        FFNetIOResult* icCurr = FF_LIST_GET(FFNetIOResult, *result, i);
        if (!ffStrbufEqual(&icPrev->name, &icCurr->name)) {
            return "Network interface name changed";
        }

        static_assert(sizeof(FFNetIOResult) - offsetof(FFNetIOResult, txBytes) == sizeof(uint64_t) * 8, "Unexpected struct FFNetIOResult layout");
        for (size_t off = offsetof(FFNetIOResult, txBytes); off < sizeof(FFNetIOResult); off += sizeof(uint64_t)) {
            uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
            uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
            uint64_t temp = *currValue;
            *currValue -= *prevValue;
            *currValue /= (time2 - time1) / 1000 /* seconds */;
            *prevValue = temp;
        }
    }
    time1 = time2;

    return NULL;
}