1 /*
2 SPDX-FileCopyrightText: 2011 Joris Guisson <joris.guisson@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "trafficshapedsocket.h"
8
9 #include "socket.h"
10 #include "speed.h"
11 #include <QStringList>
12 #include <util/functions.h>
13
14 const bt::Uint32 OUTPUT_BUFFER_SIZE = 16393;
15
16 using namespace bt;
17
18 namespace net
19 {
TrafficShapedSocket(SocketDevice * sock)20 TrafficShapedSocket::TrafficShapedSocket(SocketDevice *sock)
21 : rdr(nullptr)
22 , up_gid(0)
23 , down_gid(0)
24 , sock(sock)
25 , mutex(QMutex::Recursive)
26 {
27 down_speed = new Speed();
28 up_speed = new Speed();
29 }
30
TrafficShapedSocket(int fd,int ip_version)31 TrafficShapedSocket::TrafficShapedSocket(int fd, int ip_version)
32 : rdr(nullptr)
33 , up_gid(0)
34 , down_gid(0)
35 , mutex(QMutex::Recursive)
36 {
37 sock = new Socket(fd, ip_version);
38 down_speed = new Speed();
39 up_speed = new Speed();
40 }
41
TrafficShapedSocket(bool tcp,int ip_version)42 TrafficShapedSocket::TrafficShapedSocket(bool tcp, int ip_version)
43 : rdr(nullptr)
44 , up_gid(0)
45 , down_gid(0)
46 , mutex(QMutex::Recursive)
47 {
48 Socket *socket = new Socket(tcp, ip_version);
49
50 QString iface = NetworkInterface();
51 QStringList ips = NetworkInterfaceIPAddresses(iface);
52 if (ips.size() > 0)
53 socket->bind(ips.front(), 0, false);
54
55 sock = socket;
56 down_speed = new Speed();
57 up_speed = new Speed();
58 }
59
~TrafficShapedSocket()60 TrafficShapedSocket::~TrafficShapedSocket()
61 {
62 delete up_speed;
63 delete down_speed;
64 delete sock;
65 }
66
setGroupID(Uint32 gid,bool upload)67 void TrafficShapedSocket::setGroupID(Uint32 gid, bool upload)
68 {
69 if (upload)
70 up_gid = gid;
71 else
72 down_gid = gid;
73 }
74
getDownloadRate() const75 int TrafficShapedSocket::getDownloadRate() const
76 {
77 // getRate is atomic
78 return down_speed->getRate();
79 }
80
getUploadRate() const81 int TrafficShapedSocket::getUploadRate() const
82 {
83 // getRate is atomic
84 return up_speed->getRate();
85 }
86
updateSpeeds(bt::TimeStamp now)87 void TrafficShapedSocket::updateSpeeds(bt::TimeStamp now)
88 {
89 mutex.lock();
90 up_speed->update(now);
91 down_speed->update(now);
92 mutex.unlock();
93 }
94
95 static bt::Uint8 input_buffer[OUTPUT_BUFFER_SIZE];
96
read(bt::Uint32 max_bytes_to_read,bt::TimeStamp now)97 Uint32 TrafficShapedSocket::read(bt::Uint32 max_bytes_to_read, bt::TimeStamp now)
98 {
99 Uint32 br = 0;
100 bool no_limit = (max_bytes_to_read == 0);
101 Uint32 ba = sock->bytesAvailable();
102 if (ba == 0) {
103 // For some strange reason, sometimes bytesAvailable returns 0, while there are
104 // bytes to read, so give ba the maximum value it can be
105 ba = max_bytes_to_read > 0 ? max_bytes_to_read : OUTPUT_BUFFER_SIZE;
106 }
107
108 while ((br < max_bytes_to_read || no_limit) && ba > 0) {
109 Uint32 tr = ba;
110 if (tr > OUTPUT_BUFFER_SIZE)
111 tr = OUTPUT_BUFFER_SIZE;
112 if (!no_limit && tr + br > max_bytes_to_read)
113 tr = max_bytes_to_read - br;
114
115 int ret = sock->recv(input_buffer, tr);
116 if (ret > 0) {
117 mutex.lock();
118 down_speed->onData(ret, now);
119 mutex.unlock();
120 if (rdr) {
121 postProcess(input_buffer, ret);
122 rdr->onDataReady(input_buffer, ret);
123 }
124 br += ret;
125 ba -= ret;
126 } else if (ret < 0) {
127 return br;
128 } else {
129 sock->close();
130 return br;
131 }
132 }
133 return br;
134 }
135
postProcess(Uint8 * data,Uint32 size)136 void TrafficShapedSocket::postProcess(Uint8 *data, Uint32 size)
137 {
138 Q_UNUSED(data);
139 Q_UNUSED(size);
140 }
141 }
142