/work/toxav/bwcontroller.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2016-2018 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/util.h" |
18 | | |
19 | 36 | #define BWC_PACKET_ID 196 |
20 | 5 | #define BWC_SEND_INTERVAL_MS 950 // 0.95s |
21 | 396 | #define BWC_AVG_PKT_COUNT 20 |
22 | 450 | #define BWC_AVG_LOSS_OVER_CYCLES_COUNT 30 |
23 | | |
24 | | typedef struct BWCCycle { |
25 | | uint32_t last_recv_timestamp; /* Last recv update time stamp */ |
26 | | uint32_t last_sent_timestamp; /* Last sent update time stamp */ |
27 | | uint32_t last_refresh_timestamp; /* Last refresh time stamp */ |
28 | | |
29 | | uint32_t lost; |
30 | | uint32_t recv; |
31 | | } BWCCycle; |
32 | | |
33 | | typedef struct BWCRcvPkt { |
34 | | uint32_t packet_length_array[BWC_AVG_PKT_COUNT]; |
35 | | RingBuffer *rb; |
36 | | } BWCRcvPkt; |
37 | | |
38 | | struct BWController { |
39 | | m_cb *mcb; |
40 | | void *mcb_user_data; |
41 | | |
42 | | Messenger *m; |
43 | | Tox *tox; |
44 | | uint32_t friend_number; |
45 | | |
46 | | BWCCycle cycle; |
47 | | |
48 | | BWCRcvPkt rcvpkt; /* To calculate average received packet (this means split parts, not the full message!) */ |
49 | | |
50 | | uint32_t packet_loss_counted_cycles; |
51 | | Mono_Time *bwc_mono_time; |
52 | | }; |
53 | | |
54 | | struct BWCMessage { |
55 | | uint32_t lost; |
56 | | uint32_t recv; |
57 | | }; |
58 | | |
59 | | static int bwc_handle_data(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object); |
60 | | static int bwc_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length); |
61 | | static void send_update(BWController *bwc); |
62 | | |
63 | | BWController *bwc_new(Messenger *m, Tox *tox, uint32_t friendnumber, m_cb *mcb, void *mcb_user_data, |
64 | | Mono_Time *bwc_mono_time) |
65 | 18 | { |
66 | 18 | BWController *retu = (BWController *)calloc(1, sizeof(BWController)); |
67 | | |
68 | 18 | if (retu == nullptr) { |
69 | 0 | return nullptr; |
70 | 0 | } |
71 | | |
72 | 18 | LOGGER_DEBUG(m->log, "Creating bandwidth controller"); |
73 | 18 | retu->mcb = mcb; |
74 | 18 | retu->mcb_user_data = mcb_user_data; |
75 | 18 | retu->m = m; |
76 | 18 | retu->friend_number = friendnumber; |
77 | 18 | retu->bwc_mono_time = bwc_mono_time; |
78 | 18 | const uint64_t now = current_time_monotonic(bwc_mono_time); |
79 | 18 | retu->cycle.last_sent_timestamp = now; |
80 | 18 | retu->cycle.last_refresh_timestamp = now; |
81 | 18 | retu->tox = tox; |
82 | 18 | retu->rcvpkt.rb = rb_new(BWC_AVG_PKT_COUNT); |
83 | 18 | retu->cycle.lost = 0; |
84 | 18 | retu->cycle.recv = 0; |
85 | 18 | retu->packet_loss_counted_cycles = 0; |
86 | | |
87 | | /* Fill with zeros */ |
88 | 378 | for (int i = 0; i < BWC_AVG_PKT_COUNT; ++i) { |
89 | 360 | rb_write(retu->rcvpkt.rb, &retu->rcvpkt.packet_length_array[i]); |
90 | 360 | } |
91 | | |
92 | 18 | m_callback_rtp_packet(m, friendnumber, BWC_PACKET_ID, bwc_handle_data, retu); |
93 | 18 | return retu; |
94 | 18 | } |
95 | | |
96 | | void bwc_kill(BWController *bwc) |
97 | 18 | { |
98 | 18 | if (bwc == nullptr) { |
99 | 0 | return; |
100 | 0 | } |
101 | | |
102 | 18 | m_callback_rtp_packet(bwc->m, bwc->friend_number, BWC_PACKET_ID, nullptr, nullptr); |
103 | 18 | rb_kill(bwc->rcvpkt.rb); |
104 | 18 | free(bwc); |
105 | 18 | } |
106 | | |
107 | | void bwc_add_lost(BWController *bwc, uint32_t bytes_lost) |
108 | 0 | { |
109 | 0 | if (bwc == nullptr) { |
110 | 0 | return; |
111 | 0 | } |
112 | | |
113 | 0 | if (bytes_lost > 0) { |
114 | 0 | LOGGER_DEBUG(bwc->m->log, "BWC lost(1): %d", (int)bytes_lost); |
115 | 0 | bwc->cycle.lost += bytes_lost; |
116 | 0 | send_update(bwc); |
117 | 0 | } |
118 | 0 | } |
119 | | |
120 | | void bwc_add_recv(BWController *bwc, uint32_t recv_bytes) |
121 | 225 | { |
122 | 225 | if (bwc == nullptr || recv_bytes == 0) { |
123 | 0 | return; |
124 | 0 | } |
125 | | |
126 | 225 | ++bwc->packet_loss_counted_cycles; |
127 | 225 | bwc->cycle.recv += recv_bytes; |
128 | 225 | send_update(bwc); |
129 | 225 | } |
130 | | |
131 | | static void send_update(BWController *bwc) |
132 | 225 | { |
133 | 225 | if (bwc->packet_loss_counted_cycles > BWC_AVG_LOSS_OVER_CYCLES_COUNT && |
134 | 225 | current_time_monotonic(bwc->bwc_mono_time) - bwc->cycle.last_sent_timestamp > BWC_SEND_INTERVAL_MS) { |
135 | 5 | bwc->packet_loss_counted_cycles = 0; |
136 | | |
137 | 5 | if (bwc->cycle.lost != 0) { |
138 | 0 | LOGGER_DEBUG(bwc->m->log, "%p Sent update rcv: %u lost: %u percent: %f %%", |
139 | 0 | (void *)bwc, bwc->cycle.recv, bwc->cycle.lost, |
140 | 0 | ((double)bwc->cycle.lost / (bwc->cycle.recv + bwc->cycle.lost)) * 100.0); |
141 | 0 | uint8_t bwc_packet[sizeof(struct BWCMessage) + 1]; |
142 | 0 | size_t offset = 0; |
143 | |
|
144 | 0 | bwc_packet[offset] = BWC_PACKET_ID; // set packet ID |
145 | 0 | ++offset; |
146 | |
|
147 | 0 | offset += net_pack_u32(bwc_packet + offset, bwc->cycle.lost); |
148 | 0 | offset += net_pack_u32(bwc_packet + offset, bwc->cycle.recv); |
149 | 0 | assert(offset == sizeof(bwc_packet)); |
150 | | |
151 | 0 | if (bwc_send_custom_lossy_packet(bwc->tox, bwc->friend_number, bwc_packet, sizeof(bwc_packet)) == -1) { |
152 | 0 | char *netstrerror = net_new_strerror(net_error()); |
153 | 0 | char *stdstrerror = net_new_strerror(errno); |
154 | 0 | LOGGER_WARNING(bwc->m->log, "BWC send failed (len: %u)! std error: %s, net error %s", |
155 | 0 | (unsigned)sizeof(bwc_packet), stdstrerror, netstrerror); |
156 | 0 | net_kill_strerror(stdstrerror); |
157 | 0 | net_kill_strerror(netstrerror); |
158 | 0 | } |
159 | 0 | } |
160 | | |
161 | 5 | bwc->cycle.last_sent_timestamp = current_time_monotonic(bwc->bwc_mono_time); |
162 | 5 | bwc->cycle.lost = 0; |
163 | 5 | bwc->cycle.recv = 0; |
164 | 5 | } |
165 | 225 | } |
166 | | |
167 | | static int on_update(BWController *bwc, const struct BWCMessage *msg) |
168 | 0 | { |
169 | 0 | LOGGER_DEBUG(bwc->m->log, "%p Got update from peer", (void *)bwc); |
170 | | |
171 | | /* Peers sent update too soon */ |
172 | 0 | if (bwc->cycle.last_recv_timestamp + BWC_SEND_INTERVAL_MS > current_time_monotonic(bwc->bwc_mono_time)) { |
173 | 0 | LOGGER_INFO(bwc->m->log, "%p Rejecting extra update", (void *)bwc); |
174 | 0 | return -1; |
175 | 0 | } |
176 | | |
177 | 0 | bwc->cycle.last_recv_timestamp = current_time_monotonic(bwc->bwc_mono_time); |
178 | |
|
179 | 0 | const uint32_t lost = msg->lost; |
180 | |
|
181 | 0 | if (lost != 0 && bwc->mcb != nullptr) { |
182 | 0 | const uint32_t recv = msg->recv; |
183 | 0 | LOGGER_DEBUG(bwc->m->log, "recved: %u lost: %u percentage: %f %%", recv, lost, |
184 | 0 | ((double)lost / (recv + lost)) * 100.0); |
185 | 0 | bwc->mcb(bwc, bwc->friend_number, |
186 | 0 | (float)lost / (recv + lost), |
187 | 0 | bwc->mcb_user_data); |
188 | 0 | } |
189 | |
|
190 | 0 | return 0; |
191 | 0 | } |
192 | | |
193 | | /* |
194 | | * return -1 on failure, 0 on success |
195 | | * |
196 | | */ |
197 | | static int bwc_send_custom_lossy_packet(Tox *tox, int32_t friendnumber, const uint8_t *data, uint32_t length) |
198 | 0 | { |
199 | 0 | Tox_Err_Friend_Custom_Packet error; |
200 | 0 | tox_friend_send_lossy_packet(tox, friendnumber, data, (size_t)length, &error); |
201 | |
|
202 | 0 | if (error == TOX_ERR_FRIEND_CUSTOM_PACKET_OK) { |
203 | 0 | return 0; |
204 | 0 | } |
205 | | |
206 | 0 | return -1; |
207 | 0 | } |
208 | | |
209 | | static int bwc_handle_data(Messenger *m, uint32_t friend_number, const uint8_t *data, uint16_t length, void *object) |
210 | 0 | { |
211 | 0 | BWController *bwc = (BWController *)object; |
212 | |
|
213 | 0 | if (length - 1 != sizeof(struct BWCMessage)) { |
214 | 0 | return -1; |
215 | 0 | } |
216 | | |
217 | 0 | size_t offset = 1; // Ignore packet id. |
218 | 0 | struct BWCMessage msg; |
219 | 0 | offset += net_unpack_u32(data + offset, &msg.lost); |
220 | 0 | offset += net_unpack_u32(data + offset, &msg.recv); |
221 | 0 | assert(offset == length); |
222 | | |
223 | 0 | return on_update(bwc, &msg); |
224 | 0 | } |