Coverage Report

Created: 2026-10-24 08:16

/work/toxav/bwcontroller.c
Line
Count
Source (jump to first uncovered line)
1
/* SPDX-License-Identifier: GPL-3.0-or-later
2
 * Copyright © 2016-2026 The TokTok team.
3
 * Copyright © 2013-2015 Tox project.
4
 */
5
#include "bwcontroller.h"
6
7
#include <assert.h>
8
#include <errno.h>
9
#include <stdlib.h>
10
#include <string.h>
11
12
#include "ring_buffer.h"
13
14
#include "../toxcore/ccompat.h"
15
#include "../toxcore/logger.h"
16
#include "../toxcore/mono_time.h"
17
#include "../toxcore/network.h"
18
#include "../toxcore/util.h"
19
20
21
35
#define BWC_SEND_INTERVAL_MS 950     // 0.95s
22
462
#define BWC_AVG_PKT_COUNT 20
23
676
#define BWC_AVG_LOSS_OVER_CYCLES_COUNT 30
24
25
typedef struct BWCCycle {
26
    uint32_t last_recv_timestamp; /* Last recv update time stamp */
27
    uint32_t last_sent_timestamp; /* Last sent update time stamp */
28
    uint32_t last_refresh_timestamp; /* Last refresh time stamp */
29
30
    uint32_t lost;
31
    uint32_t recv;
32
} BWCCycle;
33
34
typedef struct BWCRcvPkt {
35
    uint32_t packet_length_array[BWC_AVG_PKT_COUNT];
36
    RingBuffer *_Nonnull rb;
37
} BWCRcvPkt;
38
39
struct BWController {
40
    bwc_loss_report_cb *_Nullable mcb;
41
    void *_Nullable mcb_user_data;
42
    bwc_send_packet_cb *_Nullable send_packet;
43
    void *_Nullable send_packet_user_data;
44
    const Logger *_Nonnull log;
45
    uint32_t friend_number;
46
47
    BWCCycle cycle;
48
49
    BWCRcvPkt rcvpkt; /* To calculate average received packet (this means split parts, not the full message!) */
50
51
    uint32_t packet_loss_counted_cycles;
52
    Mono_Time *_Nonnull bwc_mono_time;
53
    bool bwc_receive_active; /* if this is set to false then incoming bwc packets will not be processed by bwc_handle_data() */
54
};
55
56
struct BWCMessage {
57
    uint32_t lost;
58
    uint32_t recv;
59
};
60
61
static void send_update(BWController *_Nonnull bwc);
62
63
64
BWController *bwc_new(const Logger *log, uint32_t friendnumber,
65
                      bwc_loss_report_cb *mcb, void *mcb_user_data,
66
                      bwc_send_packet_cb *send_packet, void *send_packet_user_data,
67
                      Mono_Time *bwc_mono_time)
68
21
{
69
21
    BWController *retu = (BWController *)calloc(1, sizeof(BWController));
70
71
21
    if (retu == nullptr) {
72
0
        return nullptr;
73
0
    }
74
75
21
    LOGGER_DEBUG(log, "Creating bandwidth controller");
76
77
21
    retu->mcb = mcb;
78
21
    retu->mcb_user_data = mcb_user_data;
79
21
    retu->send_packet = send_packet;
80
21
    retu->send_packet_user_data = send_packet_user_data;
81
21
    retu->friend_number = friendnumber;
82
21
    retu->bwc_mono_time = bwc_mono_time;
83
21
    const uint64_t now = current_time_monotonic(bwc_mono_time);
84
21
    retu->cycle.last_sent_timestamp = now;
85
21
    retu->cycle.last_refresh_timestamp = now;
86
21
    retu->log = log;
87
21
    retu->bwc_receive_active = true;
88
21
    retu->rcvpkt.rb = rb_new(BWC_AVG_PKT_COUNT);
89
21
    retu->cycle.lost = 0;
90
21
    retu->cycle.recv = 0;
91
21
    retu->packet_loss_counted_cycles = 0;
92
93
    /* Fill with zeros */
94
441
    for (int i = 0; i < BWC_AVG_PKT_COUNT; ++i) {
95
420
        rb_write(retu->rcvpkt.rb, &retu->rcvpkt.packet_length_array[i]);
96
420
    }
97
98
21
    return retu;
99
21
}
100
101
void bwc_kill(BWController *bwc)
102
21
{
103
21
    if (bwc == nullptr) {
104
0
        return;
105
0
    }
106
107
21
    rb_kill(bwc->rcvpkt.rb);
108
21
    free(bwc);
109
21
}
110
111
void bwc_add_lost(BWController *bwc, uint32_t bytes_lost)
112
35
{
113
35
    if (bwc == nullptr) {
114
0
        return;
115
0
    }
116
117
35
    if (bytes_lost > 0) {
118
35
        LOGGER_DEBUG(bwc->log, "BWC lost(1): %d", (int)bytes_lost);
119
35
        bwc->cycle.lost += bytes_lost;
120
35
        send_update(bwc);
121
35
    }
122
35
}
123
124
void bwc_add_recv(BWController *bwc, uint32_t recv_bytes)
125
303
{
126
303
    if (bwc == nullptr || recv_bytes == 0) {
127
0
        return;
128
0
    }
129
130
303
    ++bwc->packet_loss_counted_cycles;
131
303
    bwc->cycle.recv += recv_bytes;
132
303
    send_update(bwc);
133
303
}
134
135
static void send_update(BWController *bwc)
136
338
{
137
338
    if (bwc->packet_loss_counted_cycles > BWC_AVG_LOSS_OVER_CYCLES_COUNT &&
138
338
            current_time_monotonic(bwc->bwc_mono_time) - bwc->cycle.last_sent_timestamp > BWC_SEND_INTERVAL_MS) {
139
7
        bwc->packet_loss_counted_cycles = 0;
140
141
7
        if (bwc->cycle.lost != 0) {
142
6
            LOGGER_DEBUG(bwc->log, "%p Sent update rcv: %u lost: %u percent: %f %%",
143
6
                         (void *)bwc, bwc->cycle.recv, bwc->cycle.lost,
144
6
                         ((double)bwc->cycle.lost / ((double)bwc->cycle.recv + (double)bwc->cycle.lost)) * 100.0);
145
6
            uint8_t bwc_packet[sizeof(struct BWCMessage) + 1];
146
6
            size_t offset = 0;
147
148
6
            bwc_packet[offset] = BWC_PACKET_ID; // set packet ID
149
6
            ++offset;
150
151
6
            offset += net_pack_u32(bwc_packet + offset, bwc->cycle.lost);
152
6
            offset += net_pack_u32(bwc_packet + offset, bwc->cycle.recv);
153
6
            assert(offset == sizeof(bwc_packet));
154
155
6
            if (bwc->send_packet != nullptr && bwc->send_packet(bwc->send_packet_user_data, bwc_packet, sizeof(bwc_packet)) != 0) {
156
1
                LOGGER_WARNING(bwc->log, "BWC send failed");
157
1
            }
158
6
        }
159
160
7
        bwc->cycle.last_sent_timestamp = current_time_monotonic(bwc->bwc_mono_time);
161
7
        bwc->cycle.lost = 0;
162
7
        bwc->cycle.recv = 0;
163
7
    }
164
338
}
165
166
static int on_update(BWController *_Nonnull bwc, const struct BWCMessage *_Nonnull msg)
167
8
{
168
8
    LOGGER_DEBUG(bwc->log, "%p Got update from peer", (void *)bwc);
169
170
    /* Peers sent update too soon */
171
8
    if (current_time_monotonic(bwc->bwc_mono_time) - bwc->cycle.last_recv_timestamp < BWC_SEND_INTERVAL_MS) {
172
2
        LOGGER_INFO(bwc->log, "%p Rejecting extra update", (void *)bwc);
173
2
        return -1;
174
2
    }
175
176
6
    bwc->cycle.last_recv_timestamp = current_time_monotonic(bwc->bwc_mono_time);
177
178
6
    const uint32_t lost = msg->lost;
179
180
6
    if (lost != 0 && bwc->mcb != nullptr) {
181
4
        const uint32_t recv = msg->recv;
182
4
        LOGGER_DEBUG(bwc->log, "recved: %u lost: %u percentage: %f %%", recv, lost,
183
4
                     ((double) lost / ((double)recv + (double)lost)) * 100.0);
184
4
        bwc->mcb(bwc, bwc->friend_number,
185
4
                 (float)((double)lost / ((double)recv + (double)lost)),
186
4
                 bwc->mcb_user_data);
187
4
    }
188
189
6
    return 0;
190
8
}
191
192
void bwc_handle_packet(BWController *bwc, const uint8_t *data, size_t length)
193
10
{
194
10
    if (bwc == nullptr) {
195
0
        return;
196
0
    }
197
198
10
    if (length - 1 != sizeof(struct BWCMessage)) {
199
2
        LOGGER_ERROR(bwc->log, "Got BWCMessage of insufficient size.");
200
2
        return;
201
2
    }
202
203
8
    if (!bwc->bwc_receive_active) {
204
0
        LOGGER_WARNING(bwc->log, "receiving not allowed!");
205
0
        return;
206
0
    }
207
208
8
    size_t offset = 1;  // Ignore packet id.
209
8
    struct BWCMessage msg;
210
8
    offset += net_unpack_u32(data + offset, &msg.lost);
211
8
    offset += net_unpack_u32(data + offset, &msg.recv);
212
8
    assert(offset == length);
213
214
8
    on_update(bwc, &msg);
215
8
}