1 /*
2 SPDX-FileCopyrightText: 2005 Joris Guisson <joris.guisson@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 #include "socketgroup.h"
7 #include "trafficshapedsocket.h"
8 #include <math.h>
9 #include <util/functions.h>
10 #include <util/log.h>
11
12 using namespace bt;
13
14 namespace net
15 {
SocketGroup(Uint32 limit,Uint32 assured_rate)16 SocketGroup::SocketGroup(Uint32 limit, Uint32 assured_rate)
17 : limit(limit)
18 , assured_rate(assured_rate)
19 {
20 prev_run_time = bt::CurrentTime();
21 group_allowance = 0;
22 group_assured = 0;
23 }
24
~SocketGroup()25 SocketGroup::~SocketGroup()
26 {
27 }
28
processUnlimited(bool up,bt::TimeStamp now)29 void SocketGroup::processUnlimited(bool up, bt::TimeStamp now)
30 {
31 std::list<TrafficShapedSocket *>::iterator i = sockets.begin();
32 while (i != sockets.end()) {
33 TrafficShapedSocket *s = *i;
34 if (s) {
35 if (up)
36 s->write(0, now);
37 else
38 s->read(0, now);
39 }
40 ++i;
41 }
42 }
43
processLimited(bool up,bt::TimeStamp now,Uint32 & allowance)44 bool SocketGroup::processLimited(bool up, bt::TimeStamp now, Uint32 &allowance)
45 {
46 Uint32 bslot = allowance / sockets.size() + 1;
47
48 std::list<TrafficShapedSocket *>::iterator itr = sockets.begin();
49
50 // while we can send and there are sockets left to send
51 while (sockets.size() > 0 && allowance > 0) {
52 Uint32 as = bslot;
53 if (as > allowance)
54 as = allowance;
55
56 TrafficShapedSocket *s = *itr;
57 if (s) {
58 Uint32 ret = 0;
59 if (up)
60 ret = s->write(as, now);
61 else
62 ret = s->read(as, now);
63
64 // if this socket did what it was supposed to do,
65 // it can have another go if stuff is leftover
66 // if it doesn't, we erase it from the list
67 if (ret != as)
68 itr = sockets.erase(itr);
69 else
70 ++itr;
71
72 if (ret > allowance)
73 allowance = 0;
74 else
75 allowance -= ret;
76 } else {
77 // 0 pointer so just erase
78 itr = sockets.erase(itr);
79 }
80
81 // wrap around if necessary
82 if (itr == sockets.end())
83 itr = sockets.begin();
84 }
85
86 return sockets.size() > 0;
87 }
88
download(Uint32 & global_allowance,bt::TimeStamp now)89 bool SocketGroup::download(Uint32 &global_allowance, bt::TimeStamp now)
90 {
91 return process(false, now, global_allowance);
92 }
93
upload(Uint32 & global_allowance,bt::TimeStamp now)94 bool SocketGroup::upload(Uint32 &global_allowance, bt::TimeStamp now)
95 {
96 return process(true, now, global_allowance);
97 }
98
calcAllowance(bt::TimeStamp now)99 void SocketGroup::calcAllowance(bt::TimeStamp now)
100 {
101 if (limit > 0)
102 group_allowance = (Uint32)ceil(1.0 * limit * (now - prev_run_time) * 0.001);
103 else
104 group_allowance = 0;
105
106 if (assured_rate > 0)
107 group_assured = (Uint32)ceil(1.0 * assured_rate * (now - prev_run_time) * 0.001);
108 else
109 group_assured = 0;
110
111 prev_run_time = now;
112 }
113
process(bool up,bt::TimeStamp now,Uint32 & global_allowance)114 bool SocketGroup::process(bool up, bt::TimeStamp now, Uint32 &global_allowance)
115 {
116 if (limit > 0) {
117 if (group_allowance == 0) {
118 clear();
119 return false;
120 }
121
122 bool ret = false;
123 if (global_allowance == 0) {
124 Uint32 p = group_allowance;
125 ret = processLimited(up, now, p);
126 group_allowance = p;
127 } else if (global_allowance <= group_allowance) {
128 Uint32 tmp = global_allowance;
129 ret = processLimited(up, now, tmp);
130
131 Uint32 done = (global_allowance - tmp);
132 if (group_allowance < done)
133 group_allowance = 0;
134 else
135 group_allowance -= done;
136
137 global_allowance = tmp;
138 } else {
139 Uint32 p = group_allowance;
140 ret = processLimited(up, now, p);
141
142 Uint32 done = (group_allowance - p);
143 if (global_allowance < done)
144 global_allowance = 0;
145 else
146 global_allowance -= done;
147
148 group_allowance = p;
149 }
150
151 // if group allowance is used up, this group can no longer do anything
152 if (group_allowance == 0) {
153 clear();
154 return false;
155 } else
156 return ret;
157 } else if (global_allowance > 0) {
158 return processLimited(up, now, global_allowance);
159 } else {
160 processUnlimited(up, now);
161 return false;
162 }
163 }
164
165 }
166