summaryrefslogtreecommitdiffstats
path: root/libkdegames/kgame/kmessageio.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkdegames/kgame/kmessageio.cpp')
-rw-r--r--libkdegames/kgame/kmessageio.cpp482
1 files changed, 482 insertions, 0 deletions
diff --git a/libkdegames/kgame/kmessageio.cpp b/libkdegames/kgame/kmessageio.cpp
new file mode 100644
index 00000000..f3353277
--- /dev/null
+++ b/libkdegames/kgame/kmessageio.cpp
@@ -0,0 +1,482 @@
+/*
+ This file is part of the KDE games library
+ Copyright (C) 2001 Burkhard Lehner (Burkhard.Lehner@gmx.de)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ KMessageIO class and subclasses KMessageSocket and KMessageDirect
+*/
+
+#include "kmessageio.h"
+#include <qsocket.h>
+#include <kdebug.h>
+#include <kprocess.h>
+#include <qfile.h>
+
+// ----------------------- KMessageIO -------------------------
+
+KMessageIO::KMessageIO (QObject *parent, const char *name)
+ : QObject (parent, name), m_id (0)
+{}
+
+KMessageIO::~KMessageIO ()
+{}
+
+void KMessageIO::setId (Q_UINT32 id)
+{
+ m_id = id;
+}
+
+Q_UINT32 KMessageIO::id ()
+{
+ return m_id;
+}
+
+// ----------------------KMessageSocket -----------------------
+
+KMessageSocket::KMessageSocket (QString host, Q_UINT16 port, QObject *parent,
+const char *name)
+ : KMessageIO (parent, name)
+{
+ mSocket = new QSocket ();
+ mSocket->connectToHost (host, port);
+ initSocket ();
+}
+
+KMessageSocket::KMessageSocket (QHostAddress host, Q_UINT16 port, QObject
+*parent, const char *name)
+ : KMessageIO (parent, name)
+{
+ mSocket = new QSocket ();
+ mSocket->connectToHost (host.toString(), port);
+ initSocket ();
+}
+
+KMessageSocket::KMessageSocket (QSocket *socket, QObject *parent, const char
+*name)
+ : KMessageIO (parent, name)
+{
+ mSocket = socket;
+ initSocket ();
+}
+
+KMessageSocket::KMessageSocket (int socketFD, QObject *parent, const char
+*name)
+ : KMessageIO (parent, name)
+{
+ mSocket = new QSocket ();
+ mSocket->setSocket (socketFD);
+ initSocket ();
+}
+
+KMessageSocket::~KMessageSocket ()
+{
+ delete mSocket;
+}
+
+bool KMessageSocket::isConnected () const
+{
+ return mSocket->state() == QSocket::Connection;
+}
+
+void KMessageSocket::send (const QByteArray &msg)
+{
+ QDataStream str (mSocket);
+ str << Q_UINT8 ('M'); // magic number for begin of message
+ str.writeBytes (msg.data(), msg.size()); // writes the length (as Q_UINT32) and the data
+}
+
+void KMessageSocket::processNewData ()
+{
+ if (isRecursive)
+ return;
+ isRecursive = true;
+
+ QDataStream str (mSocket);
+ while (mSocket->bytesAvailable() > 0)
+ {
+ if (mAwaitingHeader)
+ {
+ // Header = magic number + packet length = 5 bytes
+ if (mSocket->bytesAvailable() < 5)
+ {
+ isRecursive = false;
+ return;
+ }
+
+ // Read the magic number first. If something unexpected is found,
+ // start over again, ignoring the data that was read up to then.
+
+ Q_UINT8 v;
+ str >> v;
+ if (v != 'M')
+ {
+ kdWarning(11001) << k_funcinfo << ": Received unexpected data, magic number wrong!" << endl;
+ continue;
+ }
+
+ str >> mNextBlockLength;
+ mAwaitingHeader = false;
+ }
+ else
+ {
+ // Data not completely read => wait for more
+ if (mSocket->bytesAvailable() < (Q_ULONG) mNextBlockLength)
+ {
+ isRecursive = false;
+ return;
+ }
+
+ QByteArray msg (mNextBlockLength);
+ str.readRawBytes (msg.data(), mNextBlockLength);
+
+ // send the received message
+ emit received (msg);
+
+ // Waiting for the header of the next message
+ mAwaitingHeader = true;
+ }
+ }
+
+ isRecursive = false;
+}
+
+void KMessageSocket::initSocket ()
+{
+ connect (mSocket, SIGNAL (error(int)), SIGNAL (connectionBroken()));
+ connect (mSocket, SIGNAL (connectionClosed()), SIGNAL (connectionBroken()));
+ connect (mSocket, SIGNAL (readyRead()), SLOT (processNewData()));
+ mAwaitingHeader = true;
+ mNextBlockLength = 0;
+ isRecursive = false;
+}
+
+Q_UINT16 KMessageSocket::peerPort () const
+{
+ return mSocket->peerPort();
+}
+
+QString KMessageSocket::peerName () const
+{
+ return mSocket->peerName();
+}
+
+// ----------------------KMessageDirect -----------------------
+
+KMessageDirect::KMessageDirect (KMessageDirect *partner, QObject *parent,
+const char *name)
+ : KMessageIO (parent, name), mPartner (0)
+{
+ // 0 as first parameter leaves the object unconnected
+ if (!partner)
+ return;
+
+ // Check if the other object is already connected
+ if (partner && partner->mPartner)
+ {
+ kdWarning(11001) << k_funcinfo << ": Object is already connected!" << endl;
+ return;
+ }
+
+ // Connect from us to that object
+ mPartner = partner;
+
+ // Connect the other object to us
+ partner->mPartner = this;
+}
+
+KMessageDirect::~KMessageDirect ()
+{
+ if (mPartner)
+ {
+ mPartner->mPartner = 0;
+ emit mPartner->connectionBroken();
+ }
+}
+
+bool KMessageDirect::isConnected () const
+{
+ return mPartner != 0;
+}
+
+void KMessageDirect::send (const QByteArray &msg)
+{
+ if (mPartner)
+ emit mPartner->received (msg);
+ else
+ kdError(11001) << k_funcinfo << ": Not yet connected!" << endl;
+}
+
+
+// ----------------------- KMessageProcess ---------------------------
+
+KMessageProcess::~KMessageProcess()
+{
+ kdDebug(11001) << "@@@KMessageProcess::Delete process" << endl;
+ if (mProcess)
+ {
+ mProcess->kill();
+ delete mProcess;
+ mProcess=0;
+ // Remove not send buffers
+ mQueue.setAutoDelete(true);
+ mQueue.clear();
+ // Maybe todo: delete mSendBuffer
+ }
+}
+KMessageProcess::KMessageProcess(QObject *parent, QString file) : KMessageIO(parent,0)
+{
+ // Start process
+ kdDebug(11001) << "@@@KMessageProcess::Start process" << endl;
+ mProcessName=file;
+ mProcess=new KProcess;
+ int id=0;
+ *mProcess << mProcessName << QString("%1").arg(id);
+ kdDebug(11001) << "@@@KMessageProcess::Init:Id= " << id << endl;
+ kdDebug(11001) << "@@@KMessgeProcess::Init:Processname: " << mProcessName << endl;
+ connect(mProcess, SIGNAL(receivedStdout(KProcess *, char *, int )),
+ this, SLOT(slotReceivedStdout(KProcess *, char * , int )));
+ connect(mProcess, SIGNAL(receivedStderr(KProcess *, char *, int )),
+ this, SLOT(slotReceivedStderr(KProcess *, char * , int )));
+ connect(mProcess, SIGNAL(processExited(KProcess *)),
+ this, SLOT(slotProcessExited(KProcess *)));
+ connect(mProcess, SIGNAL(wroteStdin(KProcess *)),
+ this, SLOT(slotWroteStdin(KProcess *)));
+ mProcess->start(KProcess::NotifyOnExit,KProcess::All);
+ mSendBuffer=0;
+ mReceiveCount=0;
+ mReceiveBuffer.resize(1024);
+}
+bool KMessageProcess::isConnected() const
+{
+ kdDebug(11001) << "@@@KMessageProcess::Is conencted" << endl;
+ if (!mProcess) return false;
+ return mProcess->isRunning();
+}
+void KMessageProcess::send(const QByteArray &msg)
+{
+ kdDebug(11001) << "@@@KMessageProcess:: SEND("<<msg.size()<<") to process" << endl;
+ unsigned int size=msg.size()+2*sizeof(long);
+
+ char *tmpbuffer=new char[size];
+ long *p1=(long *)tmpbuffer;
+ long *p2=p1+1;
+ kdDebug(11001) << "p1="<<p1 << "p2="<< p2 << endl;
+ memcpy(tmpbuffer+2*sizeof(long),msg.data(),msg.size());
+ *p1=0x4242aeae;
+ *p2=size;
+
+ QByteArray *buffer=new QByteArray();
+ buffer->assign(tmpbuffer,size);
+ // buffer->duplicate(msg);
+ mQueue.enqueue(buffer);
+ writeToProcess();
+}
+void KMessageProcess::writeToProcess()
+{
+ // Previous send ok and item in queue
+ if (mSendBuffer || mQueue.isEmpty()) return ;
+ mSendBuffer=mQueue.dequeue();
+ if (!mSendBuffer) return ;
+
+ // write it out to the process
+ // kdDebug(11001) << " @@@@@@ writeToProcess::SEND to process " << mSendBuffer->size() << " BYTE " << endl;
+ // char *p=mSendBuffer->data();
+ // for (int i=0;i<16;i++) printf("%02x ",(unsigned char)(*(p+i)));printf("\n");
+ mProcess->writeStdin(mSendBuffer->data(),mSendBuffer->size());
+
+}
+void KMessageProcess::slotWroteStdin(KProcess * )
+{
+ kdDebug(11001) << k_funcinfo << endl;
+ if (mSendBuffer)
+ {
+ delete mSendBuffer;
+ mSendBuffer=0;
+ }
+ writeToProcess();
+}
+
+void KMessageProcess::slotReceivedStderr(KProcess * proc, char *buffer, int buflen)
+{
+ int pid=0;
+ int len;
+ char *p;
+ char *pos;
+// kdDebug(11001)<<"############# Got stderr " << buflen << " bytes" << endl;
+
+ if (!buffer || buflen==0) return ;
+ if (proc) pid=proc->pid();
+
+
+ pos=buffer;
+ do
+ {
+ p=(char *)memchr(pos,'\n',buflen);
+ if (!p) len=buflen;
+ else len=p-pos;
+
+ QByteArray a;
+ a.setRawData(pos,len);
+ QString s(a);
+ kdDebug(11001) << "PID" <<pid<< ":" << s << endl;
+ a.resetRawData(pos,len);
+ if (p) pos=p+1;
+ buflen-=len+1;
+ }while(buflen>0);
+}
+
+
+void KMessageProcess::slotReceivedStdout(KProcess * , char *buffer, int buflen)
+{
+ kdDebug(11001) << "$$$$$$ " << k_funcinfo << ": Received " << buflen << " bytes over inter process communication" << endl;
+
+ // TODO Make a plausibility check on buflen to avoid memory overflow
+ while (mReceiveCount+buflen>=mReceiveBuffer.size()) mReceiveBuffer.resize(mReceiveBuffer.size()+1024);
+ memcpy(mReceiveBuffer.data()+mReceiveCount,buffer,buflen);
+ mReceiveCount+=buflen;
+
+ // Possbile message
+ while (mReceiveCount>2*sizeof(long))
+ {
+ long *p1=(long *)mReceiveBuffer.data();
+ long *p2=p1+1;
+ unsigned int len;
+ if (*p1!=0x4242aeae)
+ {
+ kdDebug(11001) << k_funcinfo << ": Cookie error...transmission failure...serious problem..." << endl;
+// for (int i=0;i<mReceiveCount;i++) fprintf(stderr,"%02x ",mReceiveBuffer[i]);fprintf(stderr,"\n");
+ }
+ len=(int)(*p2);
+ if (len<2*sizeof(long))
+ {
+ kdDebug(11001) << k_funcinfo << ": Message size error" << endl;
+ break;
+ }
+ if (len<=mReceiveCount)
+ {
+ kdDebug(11001) << k_funcinfo << ": Got message with len " << len << endl;
+
+ QByteArray msg;
+ // msg.setRawData(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
+ msg.duplicate(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
+ emit received(msg);
+ // msg.resetRawData(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
+ // Shift buffer
+ if (len<mReceiveCount)
+ {
+ memmove(mReceiveBuffer.data(),mReceiveBuffer.data()+len,mReceiveCount-len);
+ }
+ mReceiveCount-=len;
+ }
+ else break;
+ }
+}
+
+void KMessageProcess::slotProcessExited(KProcess * /*p*/)
+{
+ kdDebug(11001) << "Process exited (slot)" << endl;
+ emit connectionBroken();
+ delete mProcess;
+ mProcess=0;
+}
+
+
+// ----------------------- KMessageFilePipe ---------------------------
+KMessageFilePipe::KMessageFilePipe(QObject *parent,QFile *readfile,QFile *writefile) : KMessageIO(parent,0)
+{
+ mReadFile=readfile;
+ mWriteFile=writefile;
+ mReceiveCount=0;
+ mReceiveBuffer.resize(1024);
+}
+
+KMessageFilePipe::~KMessageFilePipe()
+{
+}
+
+bool KMessageFilePipe::isConnected () const
+{
+ return (mReadFile!=0)&&(mWriteFile!=0);
+}
+
+void KMessageFilePipe::send(const QByteArray &msg)
+{
+ unsigned int size=msg.size()+2*sizeof(long);
+
+ char *tmpbuffer=new char[size];
+ long *p1=(long *)tmpbuffer;
+ long *p2=p1+1;
+ memcpy(tmpbuffer+2*sizeof(long),msg.data(),msg.size());
+ *p1=0x4242aeae;
+ *p2=size;
+
+ QByteArray buffer;
+ buffer.assign(tmpbuffer,size);
+ mWriteFile->writeBlock(buffer);
+ mWriteFile->flush();
+ /*
+ fprintf(stderr,"+++ KMessageFilePipe:: SEND(%d to parent) realsize=%d\n",msg.size(),buffer.size());
+ for (int i=0;i<buffer.size();i++) fprintf(stderr,"%02x ",buffer[i]);fprintf(stderr,"\n");
+ fflush(stderr);
+ */
+}
+
+void KMessageFilePipe::exec()
+{
+
+ // According to BL: Blocking read is ok
+ // while(mReadFile->atEnd()) { usleep(100); }
+
+ int ch=mReadFile->getch();
+
+ while (mReceiveCount>=mReceiveBuffer.size()) mReceiveBuffer.resize(mReceiveBuffer.size()+1024);
+ mReceiveBuffer[mReceiveCount]=(char)ch;
+ mReceiveCount++;
+
+ // Change for message
+ if (mReceiveCount>=2*sizeof(long))
+ {
+ long *p1=(long *)mReceiveBuffer.data();
+ long *p2=p1+1;
+ unsigned int len;
+ if (*p1!=0x4242aeae)
+ {
+ fprintf(stderr,"KMessageFilePipe::exec:: Cookie error...transmission failure...serious problem...\n");
+// for (int i=0;i<16;i++) fprintf(stderr,"%02x ",mReceiveBuffer[i]);fprintf(stderr,"\n");
+ }
+ len=(int)(*p2);
+ if (len==mReceiveCount)
+ {
+ //fprintf(stderr,"KMessageFilePipe::exec:: Got Message with len %d\n",len);
+
+ QByteArray msg;
+ //msg.setRawData(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
+ msg.duplicate(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
+ emit received(msg);
+ //msg.resetRawData(mReceiveBuffer.data()+2*sizeof(long),len-2*sizeof(long));
+ mReceiveCount=0;
+ }
+ }
+
+
+ return ;
+
+
+}
+
+#include "kmessageio.moc"