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)