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