summaryrefslogtreecommitdiff
authorzecke <zecke>2002-10-01 14:27:17 (UTC)
committer zecke <zecke>2002-10-01 14:27:17 (UTC)
commitbba0335bbea81519beafb7fec1979a0abbd8a7ea (patch) (side-by-side diff)
treeee334cf518c59582a36a3dd24238a05dfc3535a2
parentef8d0a15d706b0e230f052efcb1eab6f905a8737 (diff)
downloadopie-bba0335bbea81519beafb7fec1979a0abbd8a7ea.zip
opie-bba0335bbea81519beafb7fec1979a0abbd8a7ea.tar.gz
opie-bba0335bbea81519beafb7fec1979a0abbd8a7ea.tar.bz2
5th try
initial checkin of X11 Opie stuff it features an IPC Server the client is todo this will become the OPIE X11 department including alternative QPEApplication, QCOP replacement
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);
+ };
+
+
+
+}