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 <QFile>
0008 #include <QObject>
0009 #include <QTextStream>
0010 #include <QtTest>
0011 #include <unistd.h>
0012 #include <util/functions.h>
0013 #include <util/log.h>
0014 #include <util/sha1hash.h>
0015 #include <util/sha1hashgen.h>
0016 #include <utp/connection.h>
0017 #include <utp/utpserver.h>
0018 #include <utp/utpsocket.h>
0019 
0020 #define BYTES_TO_SEND 100 * 1024 * 1024
0021 
0022 using namespace utp;
0023 using namespace bt;
0024 
0025 static QByteArray Generate(int size)
0026 {
0027     QByteArray ba(size, 0);
0028     /*  for (int i = 0;i < size;i+=4)
0029         {
0030             ba[i] = 'A';
0031             ba[i+1] = 'B';
0032             ba[i+2] = 'C';
0033             ba[i+3] = 'D';
0034         }
0035         */
0036     for (int i = 0; i < size; i++) {
0037         ba[i] = i % 256;
0038     }
0039     return ba;
0040 }
0041 /*
0042 static void Dump(const bt::Uint8* pkt, bt::Uint32 size,const QString & file)
0043 {
0044     QFile fptr(file);
0045     if (fptr.open(QIODevice::Text|QIODevice::WriteOnly))
0046     {
0047         QTextStream out(&fptr);
0048         out << "Packet: " << size << ::endl;
0049         out << "Hash:   " << bt::SHA1Hash::generate(pkt,size).toString() << ::endl;
0050 
0051         for (bt::Uint32 i = 0;i < size;i+=4)
0052         {
0053             if (i > 0 && i % 32 == 0)
0054                 out << ::endl;
0055 
0056             out << QString("%1%2%3%4 ")
0057                     .arg(pkt[i],2,16)
0058                     .arg(pkt[i+1],2,16)
0059                     .arg(pkt[i+2],2,16)
0060                     .arg(pkt[i+3],2,16);
0061         }
0062 
0063         out << ::endl << ::endl << ::endl;
0064     }
0065 }
0066 */
0067 
0068 class SendThread : public QThread
0069 {
0070 public:
0071     SendThread(Connection::Ptr outgoing, UTPServer &srv, QObject *parent = nullptr)
0072         : QThread(parent)
0073         , outgoing(outgoing)
0074         , srv(srv)
0075     {
0076     }
0077 
0078     void run() override
0079     {
0080         int step = 64 * 1024;
0081         QByteArray data = Generate(step);
0082         bt::SHA1HashGen hgen;
0083 
0084         bt::Int64 sent = 0;
0085         int off = 0;
0086         net::Poll poller;
0087         while (sent < BYTES_TO_SEND && outgoing->connectionState() != CS_CLOSED) {
0088             int to_send = step - off;
0089             int ret = outgoing->send((const bt::Uint8 *)data.data() + off, to_send);
0090             if (ret > 0) {
0091                 hgen.update((const bt::Uint8 *)data.data() + off, ret);
0092                 sent += ret;
0093                 off += ret;
0094                 off = off % step;
0095                 // Out(SYS_UTP|LOG_DEBUG) << "Transmitted " << sent << endl;
0096             } else if (ret == 0) {
0097                 srv.preparePolling(&poller, net::Poll::OUTPUT, outgoing);
0098                 poller.poll(1000);
0099             } else {
0100                 break;
0101             }
0102         }
0103 
0104         sleep(2);
0105         Out(SYS_UTP | LOG_DEBUG) << "Transmitted " << sent << endl;
0106         outgoing->dumpStats();
0107         outgoing->close();
0108         hgen.end();
0109         sent_hash = hgen.get();
0110     }
0111 
0112     Connection::Ptr outgoing;
0113     bt::SHA1Hash sent_hash;
0114     UTPServer &srv;
0115 };
0116 
0117 class TransmitTest : public QEventLoop
0118 {
0119     Q_OBJECT
0120 public:
0121     TransmitTest(QObject *parent = nullptr)
0122         : QEventLoop(parent)
0123     {
0124     }
0125 
0126     void accepted()
0127     {
0128         incoming = srv.acceptedConnection().toStrongRef();
0129         incoming->setBlocking(true);
0130         exit();
0131     }
0132 
0133     void startConnect()
0134     {
0135         net::Address addr("127.0.0.1", port);
0136         outgoing = srv.connectTo(addr);
0137         outgoing->setBlocking(true);
0138     }
0139 
0140     void endEventLoop()
0141     {
0142         exit();
0143     }
0144 
0145 private Q_SLOTS:
0146     void initTestCase()
0147     {
0148         bt::InitLog("transmittest.log", false, true, false);
0149 
0150         port = 50000;
0151         while (port < 60000) {
0152             if (!srv.changePort(port))
0153                 port++;
0154             else
0155                 break;
0156         }
0157 
0158         srv.setCreateSockets(false);
0159         srv.start();
0160     }
0161 
0162     void cleanupTestCase()
0163     {
0164         srv.stop();
0165     }
0166 
0167     void testConnect()
0168     {
0169         connect(&srv, &utp::UTPServer::accepted, this, &TransmitTest::accepted, Qt::QueuedConnection);
0170         QTimer::singleShot(0, this, &TransmitTest::startConnect);
0171         QTimer::singleShot(5000, this, &TransmitTest::endEventLoop); // use a 5 second timeout
0172         exec();
0173         QVERIFY(outgoing);
0174         QVERIFY(incoming);
0175         QVERIFY(incoming->connectionState() == CS_CONNECTED);
0176         if (outgoing->connectionState() != CS_CONNECTED)
0177             QVERIFY(outgoing->waitUntilConnected());
0178         QVERIFY(outgoing->connectionState() == CS_CONNECTED);
0179     }
0180 
0181     void testThreaded()
0182     {
0183         bt::Out(SYS_UTP | LOG_DEBUG) << "testThreaded" << bt::endl;
0184         if (outgoing->connectionState() != CS_CONNECTED || incoming->connectionState() != CS_CONNECTED) {
0185             QSKIP("Not Connected", SkipAll);
0186             return;
0187         }
0188 
0189         bt::SHA1HashGen hgen;
0190 
0191         SendThread st(outgoing, srv);
0192         st.start(); // The thread will start sending a whole bunch of data
0193         bt::Int64 received = 0;
0194         // int failures = 0;
0195         incoming->setBlocking(true);
0196         while (received < BYTES_TO_SEND && incoming->connectionState() != CS_CLOSED) {
0197             bt::Uint32 ba = incoming->bytesAvailable();
0198             if (ba > 0) {
0199                 // failures = 0;
0200                 QByteArray data(ba, 0);
0201                 int to_read = ba; //;qMin<bt::Uint32>(1024,ba);
0202                 int ret = incoming->recv((bt::Uint8 *)data.data(), to_read);
0203                 QVERIFY(ret == to_read);
0204                 if (ret > 0) {
0205                     hgen.update((bt::Uint8 *)data.data(), ret);
0206                     received += ret;
0207                     // Out(SYS_UTP|LOG_DEBUG) << "Received " << received << endl;
0208                 }
0209             } else if (incoming->connectionState() != CS_CLOSED) {
0210                 incoming->waitForData(1000);
0211             }
0212         }
0213 
0214         st.wait();
0215         Out(SYS_UTP | LOG_DEBUG) << "Received " << received << endl;
0216         incoming->dumpStats();
0217         QVERIFY(incoming->bytesAvailable() == 0);
0218         QVERIFY(outgoing->allDataSent());
0219         QVERIFY(received >= BYTES_TO_SEND);
0220 
0221         hgen.end();
0222         SHA1Hash rhash = hgen.get();
0223         Out(SYS_UTP | LOG_DEBUG) << "Received data hash: " << rhash.toString() << endl;
0224         Out(SYS_UTP | LOG_DEBUG) << "Sent data hash:     " << st.sent_hash.toString() << endl;
0225         QVERIFY(rhash == st.sent_hash);
0226     }
0227 
0228 private:
0229     Connection::Ptr incoming;
0230     Connection::Ptr outgoing;
0231     utp::UTPServer srv;
0232     int port;
0233 };
0234 
0235 QTEST_MAIN(TransmitTest)
0236 
0237 #include "transmittest.moc"