summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--x11/ipc/DESIGN42
-rw-r--r--x11/ipc/common/ocoppacket.cpp59
-rw-r--r--x11/ipc/common/ocoppacket.h64
-rw-r--r--x11/ipc/server/main.cpp13
-rw-r--r--x11/ipc/server/ocopclient.h12
-rw-r--r--x11/ipc/server/ocopserver.cpp383
-rw-r--r--x11/ipc/server/ocopserver.h95
-rw-r--r--x11/ipc/server/ocopserver.pro9
-rw-r--r--x11/ipc/test/testcon.c58
9 files changed, 735 insertions, 0 deletions
diff --git a/x11/ipc/DESIGN b/x11/ipc/DESIGN
new file mode 100644
index 0000000..fbe121b
--- a/dev/null
+++ b/x11/ipc/DESIGN
@@ -0,0 +1,42 @@
+This is the design of our Opie PDA Communication
+Protocol
+It's main purpose is to be src compatible with QCOP
+from TT and Qtopia. It's main target is to be used
+as a QCOP replacement for the X11 Windowing System.
+
+We heavily use unix domain sockets for the internal
+communication.
+We've one socket in $HOME/.opie.cop which is the
+server socket. We will communicate with the use
+of QDataStream and QByteArray.
+Internally QByteArries will be copied from the client
+to the server
+
+A package is looking similiar to this one
+
+int packet_type; // Register, Unregister, Call, Method, Reply, RegisterChannel, UnregisterChannel
+QString channel;
+QString header
+QByteArray packet
+
+Server PART:
+We keep the fds together with a list of Channels
+QMap<QString,QValueList<int>> int is the fd and QString is the channel
+name
+this makes the isRegistered stuff more easy to manage
+
+
+Client:
+RPC is currently not enabled but will be available in future versions
+I do not want to add it otherwise I'll stick too tight
+to this implementation.
+We currently only support send and forget
+isRegistered will be taken care of the client side. We can not
+use the X WindowSystem for that
+
+
+I hope this helps... be sure to look at the code
+I try to comment it
+and now go to the hacking ;)
+
+-zecke 30.09.02 \ No newline at end of file
diff --git a/x11/ipc/common/ocoppacket.cpp b/x11/ipc/common/ocoppacket.cpp
new file mode 100644
index 0000000..0d8ae84
--- a/dev/null
+++ b/x11/ipc/common/ocoppacket.cpp
@@ -0,0 +1,59 @@
+
+#include <qdatastream.h>
+
+#include "ocoppacket.h"
+
+OCOPPacket::OCOPPacket( int type,
+ const QCString& channel,
+ const QCString& header,
+ const QByteArray& array )
+ : m_type( type ), m_channel( channel ),
+ m_header( header ), m_content( array )
+{
+}
+OCOPHead OCOPPacket::head()const {
+ OCOPHead head;
+ memset(&head, 0, sizeof(head) );
+
+ head.magic = 47;
+ head.type = m_type;
+ head.chlen = m_channel.size();
+ head.funclen = m_header.size();
+ head.datalen = m_content.size();
+
+ return head;
+};
+QByteArray OCOPPacket::toByteArray()const {
+ QByteArray array;
+ QDataStream stream(array, IO_WriteOnly );
+ stream << m_type;
+ stream << m_channel;
+ stream << m_header;
+ stream << m_content;
+
+ return array;
+}
+int OCOPPacket::type()const {
+ return m_type;
+}
+QCString OCOPPacket::channel()const {
+ return m_channel;
+}
+QCString OCOPPacket::header()const {
+ return m_header;
+}
+QByteArray OCOPPacket::content()const {
+ return m_content;
+}
+void OCOPPacket::setType( int type ) {
+ m_type = type;
+}
+void OCOPPacket::setChannel( const QCString& chan ) {
+ m_channel = chan;
+}
+void OCOPPacket::setHeader( const QCString& head ) {
+ m_header = head;
+}
+void OCOPPacket::setContent( const QByteArray& arra ) {
+ m_content = arra;
+}
diff --git a/x11/ipc/common/ocoppacket.h b/x11/ipc/common/ocoppacket.h
new file mode 100644
index 0000000..490ff03
--- a/dev/null
+++ b/x11/ipc/common/ocoppacket.h
@@ -0,0 +1,64 @@
+/* GPL!*/
+
+#ifndef OPIE_OCOP_PACKET_H
+#define OPIE_OCOP_PACKET_H
+
+#include <qcstring.h>
+#include <qstring.h>
+
+/**
+ * This is the head which will be sent
+ * in advance to every packet
+ */
+struct OCOPHead {
+ int magic;
+ int type;
+ int chlen;
+ int funclen;
+ int datalen;
+};
+
+/**
+ * This is the basic packet we will
+ * use for the communication between server
+ * and client
+ */
+class OCOPPacket {
+public:
+ enum Type {
+ Register = 0, Unregister, Call,
+ Method, Reply, RegisterChannel,
+ UnregisterChannel, Return, Signal,
+ IsRegistered
+ };
+ /**
+ * the c'tor
+ * type the Type of this packet
+ * the Channel
+ * the header of the function
+ * the data inside a QByteArray
+ */
+ OCOPPacket( int type, const QCString& channel = QCString(),
+ const QCString& header = QCString(),
+ const QByteArray& array = QByteArray() );
+
+ QByteArray toByteArray()const;
+ int type()const;
+ QCString channel()const;
+ QCString header()const;
+ QByteArray content()const;
+ OCOPHead head()const;
+
+ void setType( int type );
+ void setChannel( const QCString& );
+ void setHeader(const QCString& );
+ void setContent( const QByteArray& );
+
+private:
+ int m_type;
+ QCString m_channel;
+ QCString m_header;
+ QByteArray m_content;
+};
+
+#endif
diff --git a/x11/ipc/server/main.cpp b/x11/ipc/server/main.cpp
new file mode 100644
index 0000000..bc359c9
--- a/dev/null
+++ b/x11/ipc/server/main.cpp
@@ -0,0 +1,13 @@
+#include <qapplication.h>
+#include "ocopserver.h"
+
+
+int main( int argc, char* argv[] ) {
+ QApplication app(argc, argv );
+
+ /* get the server started */
+ OCopServer server;
+
+ /* enter the event loop */
+ return app.exec();
+};
diff --git a/x11/ipc/server/ocopclient.h b/x11/ipc/server/ocopclient.h
new file mode 100644
index 0000000..056a058
--- a/dev/null
+++ b/x11/ipc/server/ocopclient.h
@@ -0,0 +1,12 @@
+#ifndef OPIE_OCOP_CLIENT_H
+#define OPIE_OCOP_CLIENT_H
+
+#include <qcstring.h>
+#include <qsocketnotifier.h>
+
+struct OCOPClient {
+ int fd;
+ QSocketNotifier* notify;
+};
+
+#endif
diff --git a/x11/ipc/server/ocopserver.cpp b/x11/ipc/server/ocopserver.cpp
new file mode 100644
index 0000000..3df574b
--- a/dev/null
+++ b/x11/ipc/server/ocopserver.cpp
@@ -0,0 +1,383 @@
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <qcstring.h>
+#include <qtimer.h>
+
+#include "ocopserver.h"
+
+OCopServer::OCopServer()
+ : QObject()
+{
+ setName( "ocopserver");
+
+ /*
+ * init the server
+ */
+ init();
+ initSocket();
+}
+OCopServer::~OCopServer() {
+// socket notifiers should be deleted
+ close(m_serverfd );
+}
+void OCopServer::init() {
+ /*
+ * we set SIGPIPE to SIG_IGN
+ * to get EPIPE on reads ;)
+ */
+ qWarning("SIGPIPE to be ignored");
+ signal(SIGPIPE, SIG_IGN );
+
+ /*
+ * initialize some variables
+ */
+ m_server = 0l;
+ m_serverError = 0l;
+}
+
+/**
+ * here we will init our server
+ * socket and bind and do the listen
+ */
+void OCopServer::initSocket() {
+ /* get the home dir */
+ QCString home( getenv("HOME") );
+ QCString path( home + "/.opie.cop");
+
+ if ( ( m_serverfd = socket( PF_UNIX, SOCK_STREAM, 0 ) ) == -1 ) {
+ qWarning("failed to create server socket");
+ /* try again later */
+ QTimer::singleShot( 400, this, SLOT(initSocket() ) );
+ return;
+ }
+ qWarning( "unlinking file %s", path.data() );
+
+ /* unlink previous sockets */
+ unlink( path.data() );
+
+ struct sockaddr_un m_address;
+ memset(&m_address, 0, sizeof(m_address ) );
+ m_address.sun_family = AF_UNIX; /* unix domain socket */
+ strcpy(m_address.sun_path, path.data() );
+ m_adrlaenge = sizeof(m_address.sun_family) + strlen(m_address.sun_path );
+
+ /* cast to make it a (sockadr*) */
+ if (bind(m_serverfd, (struct sockaddr*)&m_address, m_adrlaenge ) == -1 ) {
+ qWarning("Server could not bind try again");
+ close(m_serverfd);
+ QTimer::singleShot(400, this, SLOT(initSocket() ) );
+ return;
+ }
+
+ /* tell the kernel that we're listening and accepting
+ * 5 pending connections */
+ if (listen(m_serverfd, 5) == -1 ) {
+ qWarning("could not listen");
+ close(m_serverfd );
+ QTimer::singleShot(400, this, SLOT(initSocket() ) );
+ return;
+ }
+
+ /*
+ * now we will create two QSocketNotifier
+ * which will us notify on reads
+ * and errors
+ * we do this because they integrate
+ * nicely into the QApplication eventloop
+ */
+ m_server = new QSocketNotifier(m_serverfd, QSocketNotifier::Read, this );
+ connect( m_server, SIGNAL(activated(int) ),
+ this, SLOT(newOnServer() ) );
+
+ m_serverError = new QSocketNotifier( m_serverfd, QSocketNotifier::Exception, this);
+ connect(m_serverError, SIGNAL(activated(int) ),
+ this, SLOT(errorOnServer() ) );
+
+ qWarning("done with registering");
+}
+/**
+ * we got the possibility to read
+ * on the server
+ * this is mostly due a connect
+ * on a client side
+ * we will accept it
+ * add it to our list
+ */
+void OCopServer::newOnServer() {
+ int fd = accept();
+ if ( fd < 0 )
+ return;
+
+ /*
+ * we got a successfull new connection
+ * be happy
+ * set SocketNotifier
+ * connect it
+ * and a OCOPClient
+ */
+ qWarning("Heureka new connection %d", fd );
+
+
+ registerClient( fd );
+}
+int OCopServer::accept() {
+ /*
+ * accept it
+ * the socket is currently blocking IIRC
+ */
+ return ::accept( m_serverfd, (struct sockaddr*)&m_address, &m_adrlaenge );
+}
+void OCopServer::newOnClient( int fd ) {
+ int bug[4096];
+ //qWarning("new stuff for client on fd %d", fd );
+ errno = 0;
+ OCOPHead head;
+ memset(&head, 0, sizeof(head) );
+ int rea = ::read(fd, &head, sizeof(head) );
+ //qWarning("read %d %d", rea, errno);
+ /*
+ * I should get EPIPE but nothing like this happens
+ * so if rea == 0 and we were signaled by the notifier
+ * we close it and drop the clients...
+ */
+ if ( rea <= 0 ) {
+ deregisterClient( fd );
+ return;
+ }
+ /*
+ * OCOPHead
+ */
+ qWarning("data %s %d", bug, rea );
+
+ /*
+ * Check the magic
+ * if chcked read till EOF if magic does not match
+ * otherwise do read
+ * channel
+ * func
+ * data into mem
+ * and then send the OCOPPacket
+ *
+ */
+ if (head.magic == 47 ) {
+ qWarning("magic match");
+ QCString channel( head.chlen+1 );
+ QCString func( head.funclen+1 );
+ QByteArray data ( head.datalen );
+
+ /*
+ * we do not check for errors
+ */
+ int s = read(fd, channel.data(), head.chlen );
+ s = read(fd, func.data(), head.funclen );
+ s = read(fd, data.data(), head.datalen );
+
+ /* debug output */
+ qWarning("channel %s %d", channel.data(), head.chlen );
+ qWarning("func %s %d", func.data(), head.funclen );
+ /* debug end */
+
+ /*
+ * now that we got the complete body
+ * we need to make a package
+ * and then we need to send it to clients
+ * making a package is done here
+ * dispatching it not
+ */
+ OCOPPacket packet( head.type, channel, func, data );
+ dispatch( packet, fd );
+
+ }else{
+ qWarning("magic does not match");
+ qWarning("magic %d", head.magic );
+ }
+}
+void OCopServer::registerClient( int fd ) {
+ if (m_clients.contains(fd) )
+ return;
+
+ QSocketNotifier* notify = new QSocketNotifier(fd, QSocketNotifier::Read, this );
+ connect(notify, SIGNAL(activated(int) ),
+ this, SLOT(newOnClient(int) ) );
+ OCOPClient client;
+ client.fd = fd;
+ client.notify = notify;
+ m_clients.insert( client.fd, client );
+ qWarning("clients are up to %d", m_clients.count() );
+};
+void OCopServer::deregisterClient(int fd ) {
+ QMap<int, OCOPClient>::Iterator it = m_clients.find( fd );
+ if (it != m_clients.end() ) {
+ OCOPClient client = (*it);
+ delete client.notify;
+ m_clients.remove(fd );
+ close(fd );
+ /*
+ * TIME_ME
+ *
+ * now delete from all channels
+ * go through all channels
+ * remove the fd from the list
+ * if count becomes 0 remove the channel
+ * otherwise replace QArray<int>
+ */
+ QMap<QCString, QValueList<int> >::Iterator it;
+ for ( it = m_channels.begin(); it != m_channels.end(); ++it ) {
+ /*
+ * The channel contains this fd
+ */
+ if ( it.data().contains( fd ) ) {
+ QValueList<int> array = it.data();
+
+ /*
+ * remove channel or just replace
+ */
+ if ( array.count() == 1 ) {
+ /* is the list now invalidatet? */
+ m_channels.remove( it );
+ }else{
+ array.remove( fd );
+ it = m_channels.replace( it.key(), array );
+ }
+ }
+ } // off all channels
+ }
+ qWarning("clients are now at %d", m_clients.count() );
+};
+/**
+ * this function will evaluate
+ * the package and then do the appropriate thins
+ */
+void OCopServer::dispatch( const OCOPPacket& packet, int sourceFD ) {
+ qWarning("packet.type() == %d", packet.type() );
+ switch( packet.type() ) {
+ case OCOPPacket::Register:
+ registerClient(sourceFD );
+ break;
+ case OCOPPacket::Unregister:
+ deregisterClient(sourceFD );
+ break;
+ case OCOPPacket::Call:
+ call( packet, sourceFD );
+ break;
+ /* not implemented */
+ case OCOPPacket::Method:
+ break;
+ /* nit implemented */
+ case OCOPPacket::Reply:
+ break;
+ case OCOPPacket::RegisterChannel:
+ addChannel( packet.channel() , sourceFD );
+ break;
+ case OCOPPacket::UnregisterChannel:
+ delChannel( packet.channel(), sourceFD );
+ break;
+ /* not implemented */
+ case OCOPPacket::Return:
+ break;
+ /* not implemented :( */
+ case OCOPPacket::Signal:
+ break;
+ case OCOPPacket::IsRegistered:
+ isRegistered( packet.channel(), sourceFD );
+ break;
+ };
+}
+void OCopServer::errorOnServer() {
+ /*
+ * something is wrong on the server socket?
+ * what should we do?
+ * FIXME
+ */
+}
+QStringList OCopServer::channels() {
+ QStringList list;
+ {
+ QMap<QCString, QValueList<int> >::Iterator it;
+ for (it = m_channels.begin(); it != m_channels.end(); ++it ) {
+ list << it.key();
+ };
+ }
+ return list;
+}
+bool OCopServer::isChannelRegistered( const QCString& chan ) const{
+ return m_channels.contains( chan );
+}
+void OCopServer::addChannel( const QCString& channel,
+ int fd ) {
+ QMap<QCString, QValueList<int> >::Iterator it;
+ it = m_channels.find( channel );
+
+ /* could be empty */
+ QValueList<int> list = it.data();
+ list.append( fd );
+ it = m_channels.replace( channel, list );
+};
+void OCopServer::delChannel( const QCString& channel,
+ int fd ) {
+ if (!m_channels.contains( channel ) )
+ return;
+
+ QMap<QCString, QValueList<int> >::Iterator it;
+ it = m_channels.find( channel );
+
+ if ( it.data().contains(fd) ) {
+
+ QValueList<int> ints = it.data();
+ if ( ints.count() == 1 )
+ m_channels.remove( it );
+ else{
+ QValueList<int> ints = it.data();
+ ints.remove( fd );
+ m_channels.replace( it.key(), ints );
+ }
+ }
+}
+void OCopServer::isRegistered( const QCString& channel, int fd) {
+ OCOPHead head;
+ QCString func(2);
+
+ memset(&head, 0, sizeof(head ) );
+ head.magic = 47;
+ head.type = OCOPPacket::IsRegistered;
+ head.chlen = channel.size();
+ head.funclen = func.size();
+ head.datalen = 0;
+
+ if ( isChannelRegistered( channel ) ) {
+ //is registered
+ func[0] = 1;
+ }else{
+ func[0] = 0;
+ }
+
+ /**
+ * write the head
+ * and then channel
+ * success/failure inside func
+ */
+ write(fd, &head, sizeof(head) );
+ write(fd, channel.data(), channel.size() );
+ write(fd, func.data(), func.size() );
+}
+QValueList<int> OCopServer::clients( const QCString& channel ) {
+ return m_channels[channel];
+}
+void OCopServer::call( const OCOPPacket& p, int fd ) {
+ QValueList<int> cli = clients( p.channel() );
+ QValueList<int>::Iterator it;
+
+ OCOPHead head = p.head();
+ for (it = cli.begin(); it != cli.end(); ++it ) {
+ write( (*it), &head, sizeof(head ) );
+ write( (*it), p.channel().data(), p.channel().size() );
+ write( (*it), p.header().data(), p.header().size() );
+ write( (*it), p.content().data(), p.content().size() );
+ };
+}
diff --git a/x11/ipc/server/ocopserver.h b/x11/ipc/server/ocopserver.h
new file mode 100644
index 0000000..3e08d5b
--- a/dev/null
+++ b/x11/ipc/server/ocopserver.h
@@ -0,0 +1,95 @@
+
+#ifndef OPIE_OCOP_SERVER_H
+#define OPIE_OCOP_SERVER_H
+
+#include <sys/un.h>
+
+#include <qvaluelist.h>
+#include <qobject.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qsocketnotifier.h>
+
+#include "../common/ocoppacket.h"
+#include "ocopclient.h"
+/**
+ * This is the main server
+ * It starts the socket
+ * takes care of the receiving and sending
+ */
+class OCopServer : public QObject {
+ Q_OBJECT
+public:
+ OCopServer();
+ ~OCopServer();
+
+ QStringList channels();
+ bool isChannelRegistered(const QCString& )const;
+
+private slots:
+ void errorOnServer();// error on Server
+ void newOnServer();// accept to be taken
+ void newOnClient(int fd ); // new package received
+
+private:
+ /* replace fd with a special class in future
+ * to even work on Windoze aye aye
+ */
+ /**
+ * add a channel with a fd
+ * if the channel is not present
+ * then it'll be created
+ * if it's present we will ad the fd
+ */
+ void addChannel( const QCString& channel,
+ int fd );
+ void delChannel( const QCString& channel,
+ int fd );
+
+ /**
+ * fd was closed
+ */
+ void deregisterClient( int fd );
+
+ /**
+ * fd popped up
+ */
+ void registerClient( int fd );
+
+private:
+ void init();
+private slots:
+ void initSocket();
+private:
+ int accept();
+ void isRegistered( const QCString& channel, int );
+ void dispatch( const OCOPPacket&, int sourceFD );
+ void call( const OCOPPacket&, int sourceFD );
+ QValueList<int> clients(const QCString& channel );
+ /*
+ * All clients
+ * They include a fd and a QSocketNotifier
+ */
+ QMap<int, OCOPClient> m_clients;
+
+ /*
+ * The channels avilable
+ */
+ QMap<QCString, QValueList<int> > m_channels;
+
+ /*
+ * a notifier for our server
+ * if new stuff is arriving
+ */
+ QSocketNotifier* m_server;
+
+ /*
+ * error
+ */
+ QSocketNotifier* m_serverError;
+ int m_serverfd;
+ struct sockaddr_un m_address;
+ unsigned int m_adrlaenge;
+};
+
+#endif
diff --git a/x11/ipc/server/ocopserver.pro b/x11/ipc/server/ocopserver.pro
new file mode 100644
index 0000000..1776063
--- a/dev/null
+++ b/x11/ipc/server/ocopserver.pro
@@ -0,0 +1,9 @@
+TEMPLATE = app
+CONFIG = qt warn_on debug
+#CONFIG = qt warn_on release
+HEADERS = ../common/ocoppacket.h ocopclient.h ocopserver.h
+SOURCES = ../common/ocoppacket.cpp main.cpp ocopserver.cpp
+INCLUDEPATH += $(OPIEDIR)/include
+DEPENDPATH += $(OPIEDIR)/include
+TARGET = ocopserver
+
diff --git a/x11/ipc/test/testcon.c b/x11/ipc/test/testcon.c
new file mode 100644
index 0000000..22382b1
--- a/dev/null
+++ b/x11/ipc/test/testcon.c
@@ -0,0 +1,58 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+struct head {
+ int magic;
+ int flags;
+ int chlen;
+ int funclen;
+ int datalen;
+};
+
+int main( int argc, char* argv[] ) {
+ int fd, groesse;
+ struct sockaddr_un unix_adr;
+ struct head he;
+ char* ch = "QPE/System";
+ char* fun = "call()";
+ int test;
+ char te;
+
+
+ if( ( fd = socket(PF_UNIX, SOCK_STREAM, 0 ) ) < 0 ){
+ printf("Could not socket\n" ); return 0;
+ }
+
+ memset(&unix_adr, 0, sizeof(unix_adr ) );
+ unix_adr.sun_family = AF_UNIX;
+ strcpy(unix_adr.sun_path, "/home/ich/.opie.cop");
+ groesse = sizeof(unix_adr.sun_family) + strlen(unix_adr.sun_path);
+
+ connect(fd, (struct sockaddr*)&unix_adr, groesse );
+
+ test= 260;
+ //te = (char)test;
+ //write(fd,&test,sizeof(test));
+
+
+ he.magic = 47;
+ he.flags = 5;
+ he.chlen = strlen(ch);
+ he.funclen = strlen(fun);
+ he.datalen = 0;
+
+ for(;;){
+ write(fd,&he,sizeof(he) );
+ //write(fd,(char*)&he.magic,1);
+ write(fd,ch,strlen(ch) );
+ write(fd,fun,strlen(fun) );
+ sleep(5);
+ };
+
+
+
+}