summaryrefslogtreecommitdiff
path: root/x11/ipc/server
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 /x11/ipc/server
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 (limited to 'x11/ipc/server') (more/less context) (ignore whitespace changes)
-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
5 files changed, 512 insertions, 0 deletions
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
+