File indexing completed on 2025-01-05 04:37:32
0001 /* 0002 SPDX-FileCopyrightText: 2010 Joris Guisson <joris.guisson@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <QObject> 0008 #include <QRandomGenerator> 0009 #include <QtTest> 0010 0011 #include <util/functions.h> 0012 #include <util/log.h> 0013 #include <utp/connection.h> 0014 #include <utp/utpserver.h> 0015 #include <utp/utpsocket.h> 0016 0017 #include <ctime> 0018 #include <unistd.h> 0019 0020 #define PACKETS_TO_SEND 20 0021 #define TEST_DATA "This is the packet loss test\n" 0022 0023 using namespace utp; 0024 using namespace bt; 0025 0026 /** 0027 Server which simulates packet loss 0028 */ 0029 class PacketLossServer : public UTPServer 0030 { 0031 public: 0032 PacketLossServer(QObject *parent = nullptr) 0033 : UTPServer(parent) 0034 , packet_loss(false) 0035 , loss_factor(0.5) 0036 { 0037 setCreateSockets(false); 0038 } 0039 0040 ~PacketLossServer() override 0041 { 0042 } 0043 0044 void handlePacket(bt::Buffer::Ptr packet, const net::Address &addr) override 0045 { 0046 if (packet_loss) { 0047 // pick a random number from 0 to 100 0048 int r = QRandomGenerator::global()->bounded(100); 0049 if (r <= (int)qRound(100 * loss_factor)) { 0050 Out(SYS_UTP | LOG_DEBUG) << "Dropping packet " << endl; 0051 return; 0052 } 0053 } 0054 0055 UTPServer::handlePacket(packet, addr); 0056 } 0057 0058 void setPacketLossSimulation(bool on, float lf) 0059 { 0060 packet_loss = on; 0061 loss_factor = lf; 0062 } 0063 0064 private: 0065 bool packet_loss; 0066 float loss_factor; 0067 }; 0068 0069 class SendThread : public QThread 0070 { 0071 public: 0072 SendThread(Connection::Ptr outgoing, QObject *parent = nullptr) 0073 : QThread(parent) 0074 , outgoing(outgoing) 0075 { 0076 } 0077 0078 void run() override 0079 { 0080 char test[] = TEST_DATA; 0081 int sent = 0; 0082 while (sent < PACKETS_TO_SEND && outgoing->connectionState() != CS_CLOSED) { 0083 int ret = outgoing->send((const bt::Uint8 *)test, strlen(test)); 0084 if (ret > 0) { 0085 sent++; 0086 } 0087 0088 msleep(200); 0089 } 0090 0091 while (!outgoing->allDataSent() && outgoing->connectionState() != CS_CLOSED) 0092 sleep(1); 0093 0094 Out(SYS_UTP | LOG_DEBUG) << "Transmitted " << sent << " packets " << endl; 0095 outgoing->dumpStats(); 0096 } 0097 0098 Connection::Ptr outgoing; 0099 }; 0100 0101 class PacketLoss : public QEventLoop 0102 { 0103 public: 0104 PacketLoss(QObject *parent = nullptr) 0105 : QEventLoop(parent) 0106 { 0107 } 0108 0109 void accepted() 0110 { 0111 incoming = srv.acceptedConnection().toStrongRef(); 0112 exit(); 0113 } 0114 0115 void endEventLoop() 0116 { 0117 exit(); 0118 } 0119 0120 private: 0121 void initTestCase() 0122 { 0123 bt::InitLog("packetlosstest.log"); 0124 0125 port = 50000; 0126 while (port < 60000) { 0127 if (!srv.changePort(port)) 0128 port++; 0129 else 0130 break; 0131 } 0132 0133 srv.start(); 0134 } 0135 0136 void cleanupTestCase() 0137 { 0138 srv.stop(); 0139 } 0140 0141 void testConnect() 0142 { 0143 net::Address addr("127.0.0.1", port); 0144 connect(&srv, &PacketLossServer::accepted, this, &PacketLoss::accepted, Qt::QueuedConnection); 0145 outgoing = srv.connectTo(addr).toStrongRef(); 0146 QVERIFY(outgoing); 0147 QTimer::singleShot(5000, this, &PacketLoss::endEventLoop); // use a 5 second timeout 0148 exec(); 0149 QVERIFY(incoming); 0150 } 0151 0152 void testPacketLoss() 0153 { 0154 bt::Out(SYS_UTP | LOG_DEBUG) << "testPacketLoss" << bt::endl; 0155 if (outgoing->connectionState() != CS_CONNECTED || incoming->connectionState() != CS_CONNECTED) { 0156 QSKIP("Not Connected", SkipAll); 0157 return; 0158 } 0159 0160 srv.setPacketLossSimulation(true, 0.1); // Drop 10 % of all packets 0161 SendThread st(outgoing); 0162 incoming->setBlocking(true); 0163 st.start(); // The thread will start sending a whole bunch of data 0164 int received = 0; 0165 QString received_data; 0166 0167 while (received_data.count(TEST_DATA) < PACKETS_TO_SEND) { 0168 bt::Uint32 ba = incoming->bytesAvailable(); 0169 if (ba > 0) { 0170 QByteArray data(ba, 0); 0171 int ret = incoming->recv((bt::Uint8 *)data.data(), ba); 0172 if (ret > 0) { 0173 received_data.append(data); 0174 received += ret; 0175 } 0176 } else if (incoming->connectionState() == CS_CLOSED) { 0177 Out(SYS_UTP | LOG_DEBUG) << "Connection closed " << endl; 0178 break; 0179 } else { 0180 incoming->waitForData(1000); 0181 } 0182 } 0183 0184 st.wait(); 0185 Out(SYS_UTP | LOG_DEBUG) << "Received " << received << " bytes:" << endl; 0186 Out(SYS_UTP | LOG_DEBUG) << received_data << endl; 0187 incoming->dumpStats(); 0188 QVERIFY(incoming->bytesAvailable() == 0); 0189 QVERIFY(received_data.count(TEST_DATA) == PACKETS_TO_SEND); 0190 QVERIFY(outgoing->allDataSent()); 0191 } 0192 0193 private: 0194 private: 0195 Connection::Ptr incoming; 0196 Connection::Ptr outgoing; 0197 PacketLossServer srv; 0198 int port; 0199 }; 0200 0201 QTEST_MAIN(PacketLoss)