File indexing completed on 2024-07-14 04:00:02

0001 /*
0002     This file is part of the KDE games library
0003     SPDX-FileCopyrightText: 2001 Martin Heni (kde at heni-online.de)
0004     SPDX-FileCopyrightText: 2001 Andreas Beckermann (b_mann@gmx.de)
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "kgameprocess.h"
0010 
0011 // Qt
0012 #include <QBuffer>
0013 #include <QDataStream>
0014 #include <QRandomGenerator>
0015 // Std
0016 #include <cassert>
0017 #include <cstdio>
0018 #include <cstdlib>
0019 #include <string>
0020 
0021 #define READ_BUFFER_SIZE 1024
0022 
0023 class KGameProcessPrivate
0024 {
0025 public:
0026     QFile rFile;
0027     QFile wFile;
0028     QRandomGenerator *mRandom;
0029 };
0030 
0031 // ----------------------- Process Child ---------------------------
0032 
0033 KGameProcess::KGameProcess()
0034     : QObject()
0035     , d(new KGameProcessPrivate)
0036 {
0037     mTerminate = false;
0038     // Check whether a player is set. If not create one!
0039     d->rFile.open(stdin, QIODevice::ReadOnly | QIODevice::Unbuffered);
0040     d->wFile.open(stdout, QIODevice::WriteOnly | QIODevice::Unbuffered);
0041     mMessageIO = new KMessageFilePipe(this, &d->rFile, &d->wFile);
0042     //  mMessageClient=new KMessageClient(this);
0043     //  mMessageClient->setServer(mMessageIO);
0044     //  connect (mMessageClient, SIGNAL(broadcastReceived(QByteArray,quint32)),
0045     //          this, SLOT(receivedMessage(QByteArray,quint32)));
0046     connect(mMessageIO, &KMessageFilePipe::received, this, &KGameProcess::receivedMessage);
0047 
0048     d->mRandom = new QRandomGenerator(QRandomGenerator::global()->generate());
0049 }
0050 KGameProcess::~KGameProcess()
0051 {
0052     delete d->mRandom;
0053     // delete mMessageClient;
0054     // delete mMessageServer;
0055     fprintf(stderr, "KGameProcess::destructor\n");
0056     fflush(stderr);
0057     delete mMessageIO;
0058     d->rFile.close();
0059     d->wFile.close();
0060     delete d;
0061 }
0062 
0063 bool KGameProcess::exec()
0064 {
0065     do {
0066         mMessageIO->exec();
0067     } while (!mTerminate);
0068     return true;
0069 }
0070 
0071 //    You have to do this to create a message
0072 //    QByteArray buffer;
0073 //    QDataStream wstream(buffer,QIODevice::WriteOnly);
0074 //    then stream data into the stream and call this function
0075 void KGameProcess::sendSystemMessage(QDataStream &stream, int msgid, quint32 receiver)
0076 {
0077     fprintf(stderr, "KGameProcess::sendSystemMessage to parent id=%d recv=%ld\n", msgid, (unsigned long)receiver);
0078     QByteArray a;
0079     QDataStream outstream(&a, QIODevice::WriteOnly);
0080 
0081     QBuffer *device = (QBuffer *)stream.device();
0082     QByteArray data = device->buffer();
0083 
0084     KGameMessage::createHeader(outstream, 0, receiver, msgid);
0085     outstream.writeRawData(data.data(), data.size());
0086 
0087     //  if (mMessageClient) mMessageClient->sendForward(a,2);
0088     if (mMessageIO)
0089         mMessageIO->send(a);
0090     else
0091         fprintf(stderr, "KGameProcess::sendSystemMessage:: NO IO DEVICE ... WILL FAIL\n");
0092 }
0093 
0094 void KGameProcess::sendMessage(QDataStream &stream, int msgid, quint32 receiver)
0095 {
0096     sendSystemMessage(stream, msgid + KGameMessage::IdUser, receiver);
0097 }
0098 
0099 void KGameProcess::receivedMessage(const QByteArray &receiveBuffer)
0100 {
0101     QDataStream stream(receiveBuffer);
0102     int msgid;
0103     quint32 sender;
0104     quint32 receiver;
0105     KGameMessage::extractHeader(stream, sender, receiver, msgid);
0106     fprintf(stderr, "--- KGameProcess::receivedMessage(): id=%d sender=%ld,recv=%ld\n", msgid, (unsigned long)sender, (unsigned long)receiver);
0107     switch (msgid) {
0108     case KGameMessage::IdTurn:
0109         qint8 b;
0110         stream >> b;
0111         Q_EMIT signalTurn(stream, (bool)b);
0112         break;
0113     case KGameMessage::IdIOAdded:
0114         qint16 id;
0115         stream >> id;
0116         Q_EMIT signalInit(stream, (int)id);
0117         break;
0118     default:
0119         Q_EMIT signalCommand(stream, msgid - KGameMessage::IdUser, receiver, sender);
0120         break;
0121     }
0122 }
0123 
0124 QRandomGenerator *KGameProcess::random()
0125 {
0126     return d->mRandom;
0127 }
0128 
0129 // ----------------------- KMessageFilePipe ---------------------------
0130 KMessageFilePipe::KMessageFilePipe(QObject *parent, QFile *readfile, QFile *writefile)
0131     : KMessageIO(parent)
0132 {
0133     mReadFile = readfile;
0134     mWriteFile = writefile;
0135     mReceiveCount = 0;
0136     mReceiveBuffer.resize(1024);
0137 }
0138 
0139 KMessageFilePipe::~KMessageFilePipe()
0140 {
0141 }
0142 
0143 bool KMessageFilePipe::isConnected() const
0144 {
0145     return (mReadFile != nullptr) && (mWriteFile != nullptr);
0146 }
0147 
0148 // Send to parent
0149 void KMessageFilePipe::send(const QByteArray &msg)
0150 {
0151     unsigned int size = msg.size() + 2 * sizeof(long);
0152 
0153     char *tmpbuffer = new char[size];
0154     long *p1 = (long *)tmpbuffer;
0155     long *p2 = p1 + 1;
0156     memcpy(tmpbuffer + 2 * sizeof(long), msg.data(), msg.size());
0157     *p1 = 0x4242aeae;
0158     *p2 = size;
0159 
0160     QByteArray buffer(tmpbuffer, size);
0161     mWriteFile->write(buffer);
0162     mWriteFile->flush();
0163     delete[] tmpbuffer;
0164 
0165     /* DEBUG:
0166     fprintf(stderr,"+++ KMessageFilePipe:: SEND(%d to parent) realsize=%d\n",msg.size(),buffer.size());
0167     for (int i=0;i<buffer.size();i++) fprintf(stderr,"%02x ",(unsigned char)buffer.at(i));fprintf(stderr,"\n");
0168     fflush(stderr);
0169     */
0170 }
0171 
0172 void KMessageFilePipe::exec()
0173 {
0174     // According to BL: Blocking read is ok
0175     // while(mReadFile->atEnd()) { usleep(100); }
0176     char ch;
0177     mReadFile->getChar(&ch);
0178 
0179     while (mReceiveCount >= mReceiveBuffer.size())
0180         mReceiveBuffer.resize(mReceiveBuffer.size() + 1024);
0181     mReceiveBuffer[mReceiveCount] = ch;
0182     mReceiveCount++;
0183 
0184     // Change for message
0185     if (mReceiveCount >= int(2 * sizeof(long))) {
0186         long *p1 = (long *)mReceiveBuffer.data();
0187         long *p2 = p1 + 1;
0188         int len;
0189         if (*p1 != 0x4242aeae) {
0190             fprintf(stderr, "KMessageFilePipe::exec:: Cookie error...transmission failure...serious problem...\n");
0191             fflush(stderr);
0192             //       for (int i=0;i<16;i++) fprintf(stderr,"%02x ",mReceiveBuffer[i]);fprintf(stderr,"\n");
0193         }
0194         len = (int)(*p2);
0195         if (len == mReceiveCount) {
0196             // fprintf(stderr,"KMessageFilePipe::exec:: Got Message with len %d\n",len);
0197 
0198             QByteArray msg;
0199             msg.resize(len);
0200             // msg.setRawData(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
0201             std::copy(mReceiveBuffer.begin() + 2 * sizeof(long), mReceiveBuffer.begin() + len, msg.begin());
0202             //  msg.duplicate(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
0203             Q_EMIT received(msg);
0204             // msg.resetRawData(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
0205             mReceiveCount = 0;
0206         }
0207     }
0208 
0209     return;
0210 }
0211 
0212 #include "moc_kgameprocess.cpp"