master ohmu/fastfetch-openbsd / src / detection / netio / netio.c
ohmu  ·  2026-10-15
 1#include "netio.h"
 2
 3#include "common/time.h"
 4
 5static FFlist ioCounters1;
 6static double time1;
 7
 8void ffPrepareNetIO(FFNetIOOptions* options) {
 9    if (options->detectTotal) {
10        return;
11    }
12
13    if (time1 != 0) {
14        return; // Already prepared
15    }
16
17    // The options cannot change between this call and `ffDetectNetIO`: `ffPrepareCommandOption`
18    // and `parseStructureCommand` both build them through `initStructureModuleOptions`, which
19    // merges the module object from the JSON config. So the baseline always matches the second
20    // snapshot and needs no re-validation.
21    ffListInit(&ioCounters1);
22    ffNetIOGetIoCounters(&ioCounters1, options);
23    time1 = ffTimeGetTick();
24}
25
26const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options) {
27    const char* error = nullptr;
28
29    if (options->detectTotal) {
30        error = ffNetIOGetIoCounters(result, options);
31        if (error) {
32            return error;
33        }
34        return nullptr;
35    }
36
37    if (time1 == 0) {
38        ffPrepareNetIO(options);
39    }
40
41    if (ioCounters1.length == 0) {
42        return "No network interfaces found";
43    }
44
45    double time2 = ffTimeGetTick();
46    while (time2 - time1 < (double) options->waitTime) {
47        ffTimeSleep((uint32_t) (options->waitTime - (time2 - time1)));
48        time2 = ffTimeGetTick();
49    }
50
51    error = ffNetIOGetIoCounters(result, options);
52    if (error) {
53        return error;
54    }
55
56    if (result->length != ioCounters1.length) {
57        return "Different number of network interfaces. Network change?";
58    }
59
60    for (uint32_t i = 0; i < result->length; ++i) {
61        FFNetIOResult* icPrev = FF_LIST_GET(FFNetIOResult, ioCounters1, i);
62        FFNetIOResult* icCurr = FF_LIST_GET(FFNetIOResult, *result, i);
63        if (!ffStrbufEqual(&icPrev->name, &icCurr->name)) {
64            return "Network interface name changed";
65        }
66
67        static_assert(sizeof(FFNetIOResult) - offsetof(FFNetIOResult, txBytes) == sizeof(uint64_t) * 8, "Unexpected struct FFNetIOResult layout");
68        for (size_t off = offsetof(FFNetIOResult, txBytes); off < sizeof(FFNetIOResult); off += sizeof(uint64_t)) {
69            uint64_t* prevValue = (uint64_t*) ((uint8_t*) icPrev + off);
70            uint64_t* currValue = (uint64_t*) ((uint8_t*) icCurr + off);
71            uint64_t temp = *currValue;
72            *currValue = (uint64_t) ((double) (*currValue - *prevValue) * 1000.0 / (time2 - time1)); // Calculate per second
73            *prevValue = temp;
74        }
75    }
76    time1 = time2;
77
78    return nullptr;
79}