summaryrefslogtreecommitdiff
path: root/x11/ipc
Unidiff
Diffstat (limited to 'x11/ipc') (more/less context) (show 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 @@
1This is the design of our Opie PDA Communication
2Protocol
3It's main purpose is to be src compatible with QCOP
4from TT and Qtopia. It's main target is to be used
5as a QCOP replacement for the X11 Windowing System.
6
7We heavily use unix domain sockets for the internal
8communication.
9We've one socket in $HOME/.opie.cop which is the
10server socket. We will communicate with the use
11of QDataStream and QByteArray.
12Internally QByteArries will be copied from the client
13to the server
14
15A package is looking similiar to this one
16
17int packet_type; // Register, Unregister, Call, Method, Reply, RegisterChannel, UnregisterChannel
18QString channel;
19QString header
20QByteArray packet
21
22Server PART:
23We keep the fds together with a list of Channels
24QMap<QString,QValueList<int>> int is the fd and QString is the channel
25name
26this makes the isRegistered stuff more easy to manage
27
28
29Client:
30RPC is currently not enabled but will be available in future versions
31I do not want to add it otherwise I'll stick too tight
32to this implementation.
33We currently only support send and forget
34isRegistered will be taken care of the client side. We can not
35use the X WindowSystem for that
36
37
38I hope this helps... be sure to look at the code
39I try to comment it
40and now go to the hacking ;)
41
42-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 @@
1
2#include <qdatastream.h>
3
4#include "ocoppacket.h"
5
6OCOPPacket::OCOPPacket( int type,
7 const QCString& channel,
8 const QCString& header,
9 const QByteArray& array )
10 : m_type( type ), m_channel( channel ),
11 m_header( header ), m_content( array )
12{
13}
14OCOPHead OCOPPacket::head()const {
15 OCOPHead head;
16 memset(&head, 0, sizeof(head) );
17
18 head.magic = 47;
19 head.type = m_type;
20 head.chlen = m_channel.size();
21 head.funclen = m_header.size();
22 head.datalen = m_content.size();
23
24 return head;
25};
26QByteArray OCOPPacket::toByteArray()const {
27 QByteArray array;
28 QDataStream stream(array, IO_WriteOnly );
29 stream << m_type;
30 stream << m_channel;
31 stream << m_header;
32 stream << m_content;
33
34 return array;
35}
36int OCOPPacket::type()const {
37 return m_type;
38}
39QCString OCOPPacket::channel()const {
40 return m_channel;
41}
42QCString OCOPPacket::header()const {
43 return m_header;
44}
45QByteArray OCOPPacket::content()const {
46 return m_content;
47}
48void OCOPPacket::setType( int type ) {
49 m_type = type;
50}
51void OCOPPacket::setChannel( const QCString& chan ) {
52 m_channel = chan;
53}
54void OCOPPacket::setHeader( const QCString& head ) {
55 m_header = head;
56}
57void OCOPPacket::setContent( const QByteArray& arra ) {
58 m_content = arra;
59}
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 @@
1/* GPL!*/
2
3#ifndef OPIE_OCOP_PACKET_H
4#define OPIE_OCOP_PACKET_H
5
6#include <qcstring.h>
7#include <qstring.h>
8
9/**
10 * This is the head which will be sent
11 * in advance to every packet
12 */
13struct OCOPHead {
14 int magic;
15 int type;
16 int chlen;
17 int funclen;
18 int datalen;
19};
20
21/**
22 * This is the basic packet we will
23 * use for the communication between server
24 * and client
25 */
26class OCOPPacket {
27public:
28 enum Type {
29 Register = 0, Unregister, Call,
30 Method, Reply, RegisterChannel,
31 UnregisterChannel, Return, Signal,
32 IsRegistered
33 };
34 /**
35 * the c'tor
36 * type the Type of this packet
37 * the Channel
38 * the header of the function
39 * the data inside a QByteArray
40 */
41 OCOPPacket( int type, const QCString& channel = QCString(),
42 const QCString& header = QCString(),
43 const QByteArray& array = QByteArray() );
44
45 QByteArray toByteArray()const;
46 int type()const;
47 QCString channel()const;
48 QCString header()const;
49 QByteArray content()const;
50 OCOPHead head()const;
51
52 void setType( int type );
53 void setChannel( const QCString& );
54 void setHeader(const QCString& );
55 void setContent( const QByteArray& );
56
57private:
58 int m_type;
59 QCString m_channel;
60 QCString m_header;
61 QByteArray m_content;
62};
63
64#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 @@
1#include <qapplication.h>
2#include "ocopserver.h"
3
4
5int main( int argc, char* argv[] ) {
6 QApplication app(argc, argv );
7
8 /* get the server started */
9 OCopServer server;
10
11 /* enter the event loop */
12 return app.exec();
13};
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 @@
1#ifndef OPIE_OCOP_CLIENT_H
2#define OPIE_OCOP_CLIENT_H
3
4#include <qcstring.h>
5#include <qsocketnotifier.h>
6
7struct OCOPClient {
8 int fd;
9 QSocketNotifier* notify;
10};
11
12#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 @@
1#include <errno.h>
2#include <signal.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <sys/socket.h>
7#include <sys/un.h>
8
9#include <qcstring.h>
10#include <qtimer.h>
11
12#include "ocopserver.h"
13
14OCopServer::OCopServer()
15 : QObject()
16{
17 setName( "ocopserver");
18
19 /*
20 * init the server
21 */
22 init();
23 initSocket();
24}
25OCopServer::~OCopServer() {
26// socket notifiers should be deleted
27 close(m_serverfd );
28}
29void OCopServer::init() {
30 /*
31 * we set SIGPIPE to SIG_IGN
32 * to get EPIPE on reads ;)
33 */
34 qWarning("SIGPIPE to be ignored");
35 signal(SIGPIPE, SIG_IGN );
36
37 /*
38 * initialize some variables
39 */
40 m_server = 0l;
41 m_serverError = 0l;
42}
43
44/**
45 * here we will init our server
46 * socket and bind and do the listen
47 */
48void OCopServer::initSocket() {
49 /* get the home dir */
50 QCString home( getenv("HOME") );
51 QCString path( home + "/.opie.cop");
52
53 if ( ( m_serverfd = socket( PF_UNIX, SOCK_STREAM, 0 ) ) == -1 ) {
54 qWarning("failed to create server socket");
55 /* try again later */
56 QTimer::singleShot( 400, this, SLOT(initSocket() ) );
57 return;
58 }
59 qWarning( "unlinking file %s", path.data() );
60
61 /* unlink previous sockets */
62 unlink( path.data() );
63
64 struct sockaddr_un m_address;
65 memset(&m_address, 0, sizeof(m_address ) );
66 m_address.sun_family = AF_UNIX; /* unix domain socket */
67 strcpy(m_address.sun_path, path.data() );
68 m_adrlaenge = sizeof(m_address.sun_family) + strlen(m_address.sun_path );
69
70 /* cast to make it a (sockadr*) */
71 if (bind(m_serverfd, (struct sockaddr*)&m_address, m_adrlaenge ) == -1 ) {
72 qWarning("Server could not bind try again");
73 close(m_serverfd);
74 QTimer::singleShot(400, this, SLOT(initSocket() ) );
75 return;
76 }
77
78 /* tell the kernel that we're listening and accepting
79 * 5 pending connections */
80 if (listen(m_serverfd, 5) == -1 ) {
81 qWarning("could not listen");
82 close(m_serverfd );
83 QTimer::singleShot(400, this, SLOT(initSocket() ) );
84 return;
85 }
86
87 /*
88 * now we will create two QSocketNotifier
89 * which will us notify on reads
90 * and errors
91 * we do this because they integrate
92 * nicely into the QApplication eventloop
93 */
94 m_server = new QSocketNotifier(m_serverfd, QSocketNotifier::Read, this );
95 connect( m_server, SIGNAL(activated(int) ),
96 this, SLOT(newOnServer() ) );
97
98 m_serverError = new QSocketNotifier( m_serverfd, QSocketNotifier::Exception, this);
99 connect(m_serverError, SIGNAL(activated(int) ),
100 this, SLOT(errorOnServer() ) );
101
102 qWarning("done with registering");
103}
104/**
105 * we got the possibility to read
106 * on the server
107 * this is mostly due a connect
108 * on a client side
109 * we will accept it
110 * add it to our list
111 */
112void OCopServer::newOnServer() {
113 int fd = accept();
114 if ( fd < 0 )
115 return;
116
117 /*
118 * we got a successfull new connection
119 * be happy
120 * set SocketNotifier
121 * connect it
122 * and a OCOPClient
123 */
124 qWarning("Heureka new connection %d", fd );
125
126
127 registerClient( fd );
128}
129int OCopServer::accept() {
130 /*
131 * accept it
132 * the socket is currently blocking IIRC
133 */
134 return ::accept( m_serverfd, (struct sockaddr*)&m_address, &m_adrlaenge );
135}
136void OCopServer::newOnClient( int fd ) {
137 int bug[4096];
138 //qWarning("new stuff for client on fd %d", fd );
139 errno = 0;
140 OCOPHead head;
141 memset(&head, 0, sizeof(head) );
142 int rea = ::read(fd, &head, sizeof(head) );
143 //qWarning("read %d %d", rea, errno);
144 /*
145 * I should get EPIPE but nothing like this happens
146 * so if rea == 0 and we were signaled by the notifier
147 * we close it and drop the clients...
148 */
149 if ( rea <= 0 ) {
150 deregisterClient( fd );
151 return;
152 }
153 /*
154 * OCOPHead
155 */
156 qWarning("data %s %d", bug, rea );
157
158 /*
159 * Check the magic
160 * if chcked read till EOF if magic does not match
161 * otherwise do read
162 * channel
163 * func
164 * data into mem
165 * and then send the OCOPPacket
166 *
167 */
168 if (head.magic == 47 ) {
169 qWarning("magic match");
170 QCString channel( head.chlen+1 );
171 QCString func( head.funclen+1 );
172 QByteArray data ( head.datalen );
173
174 /*
175 * we do not check for errors
176 */
177 int s = read(fd, channel.data(), head.chlen );
178 s = read(fd, func.data(), head.funclen );
179 s = read(fd, data.data(), head.datalen );
180
181 /* debug output */
182 qWarning("channel %s %d", channel.data(), head.chlen );
183 qWarning("func %s %d", func.data(), head.funclen );
184 /* debug end */
185
186 /*
187 * now that we got the complete body
188 * we need to make a package
189 * and then we need to send it to clients
190 * making a package is done here
191 * dispatching it not
192 */
193 OCOPPacket packet( head.type, channel, func, data );
194 dispatch( packet, fd );
195
196 }else{
197 qWarning("magic does not match");
198 qWarning("magic %d", head.magic );
199 }
200}
201void OCopServer::registerClient( int fd ) {
202 if (m_clients.contains(fd) )
203 return;
204
205 QSocketNotifier* notify = new QSocketNotifier(fd, QSocketNotifier::Read, this );
206 connect(notify, SIGNAL(activated(int) ),
207 this, SLOT(newOnClient(int) ) );
208 OCOPClient client;
209 client.fd = fd;
210 client.notify = notify;
211 m_clients.insert( client.fd, client );
212 qWarning("clients are up to %d", m_clients.count() );
213};
214void OCopServer::deregisterClient(int fd ) {
215 QMap<int, OCOPClient>::Iterator it = m_clients.find( fd );
216 if (it != m_clients.end() ) {
217 OCOPClient client = (*it);
218 delete client.notify;
219 m_clients.remove(fd );
220 close(fd );
221 /*
222 * TIME_ME
223 *
224 * now delete from all channels
225 * go through all channels
226 * remove the fd from the list
227 * if count becomes 0 remove the channel
228 * otherwise replace QArray<int>
229 */
230 QMap<QCString, QValueList<int> >::Iterator it;
231 for ( it = m_channels.begin(); it != m_channels.end(); ++it ) {
232 /*
233 * The channel contains this fd
234 */
235 if ( it.data().contains( fd ) ) {
236 QValueList<int> array = it.data();
237
238 /*
239 * remove channel or just replace
240 */
241 if ( array.count() == 1 ) {
242 /* is the list now invalidatet? */
243 m_channels.remove( it );
244 }else{
245 array.remove( fd );
246 it = m_channels.replace( it.key(), array );
247 }
248 }
249 } // off all channels
250 }
251 qWarning("clients are now at %d", m_clients.count() );
252};
253/**
254 * this function will evaluate
255 * the package and then do the appropriate thins
256 */
257void OCopServer::dispatch( const OCOPPacket& packet, int sourceFD ) {
258 qWarning("packet.type() == %d", packet.type() );
259 switch( packet.type() ) {
260 case OCOPPacket::Register:
261 registerClient(sourceFD );
262 break;
263 case OCOPPacket::Unregister:
264 deregisterClient(sourceFD );
265 break;
266 case OCOPPacket::Call:
267 call( packet, sourceFD );
268 break;
269 /* not implemented */
270 case OCOPPacket::Method:
271 break;
272 /* nit implemented */
273 case OCOPPacket::Reply:
274 break;
275 case OCOPPacket::RegisterChannel:
276 addChannel( packet.channel() , sourceFD );
277 break;
278 case OCOPPacket::UnregisterChannel:
279 delChannel( packet.channel(), sourceFD );
280 break;
281 /* not implemented */
282 case OCOPPacket::Return:
283 break;
284 /* not implemented :( */
285 case OCOPPacket::Signal:
286 break;
287 case OCOPPacket::IsRegistered:
288 isRegistered( packet.channel(), sourceFD );
289 break;
290 };
291}
292void OCopServer::errorOnServer() {
293 /*
294 * something is wrong on the server socket?
295 * what should we do?
296 * FIXME
297 */
298}
299QStringList OCopServer::channels() {
300 QStringList list;
301 {
302 QMap<QCString, QValueList<int> >::Iterator it;
303 for (it = m_channels.begin(); it != m_channels.end(); ++it ) {
304 list << it.key();
305 };
306 }
307 return list;
308}
309bool OCopServer::isChannelRegistered( const QCString& chan ) const{
310 return m_channels.contains( chan );
311}
312void OCopServer::addChannel( const QCString& channel,
313 int fd ) {
314 QMap<QCString, QValueList<int> >::Iterator it;
315 it = m_channels.find( channel );
316
317 /* could be empty */
318 QValueList<int> list = it.data();
319 list.append( fd );
320 it = m_channels.replace( channel, list );
321};
322void OCopServer::delChannel( const QCString& channel,
323 int fd ) {
324 if (!m_channels.contains( channel ) )
325 return;
326
327 QMap<QCString, QValueList<int> >::Iterator it;
328 it = m_channels.find( channel );
329
330 if ( it.data().contains(fd) ) {
331
332 QValueList<int> ints = it.data();
333 if ( ints.count() == 1 )
334 m_channels.remove( it );
335 else{
336 QValueList<int> ints = it.data();
337 ints.remove( fd );
338 m_channels.replace( it.key(), ints );
339 }
340 }
341}
342void OCopServer::isRegistered( const QCString& channel, int fd) {
343 OCOPHead head;
344 QCString func(2);
345
346 memset(&head, 0, sizeof(head ) );
347 head.magic = 47;
348 head.type = OCOPPacket::IsRegistered;
349 head.chlen = channel.size();
350 head.funclen = func.size();
351 head.datalen = 0;
352
353 if ( isChannelRegistered( channel ) ) {
354 //is registered
355 func[0] = 1;
356 }else{
357 func[0] = 0;
358 }
359
360 /**
361 * write the head
362 * and then channel
363 * success/failure inside func
364 */
365 write(fd, &head, sizeof(head) );
366 write(fd, channel.data(), channel.size() );
367 write(fd, func.data(), func.size() );
368}
369QValueList<int> OCopServer::clients( const QCString& channel ) {
370 return m_channels[channel];
371}
372void OCopServer::call( const OCOPPacket& p, int fd ) {
373 QValueList<int> cli = clients( p.channel() );
374 QValueList<int>::Iterator it;
375
376 OCOPHead head = p.head();
377 for (it = cli.begin(); it != cli.end(); ++it ) {
378 write( (*it), &head, sizeof(head ) );
379 write( (*it), p.channel().data(), p.channel().size() );
380 write( (*it), p.header().data(), p.header().size() );
381 write( (*it), p.content().data(), p.content().size() );
382 };
383}
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 @@
1
2#ifndef OPIE_OCOP_SERVER_H
3#define OPIE_OCOP_SERVER_H
4
5#include <sys/un.h>
6
7#include <qvaluelist.h>
8#include <qobject.h>
9#include <qmap.h>
10#include <qstring.h>
11#include <qsocketnotifier.h>
12
13#include "../common/ocoppacket.h"
14#include "ocopclient.h"
15/**
16 * This is the main server
17 * It starts the socket
18 * takes care of the receiving and sending
19 */
20class OCopServer : public QObject {
21 Q_OBJECT
22public:
23 OCopServer();
24 ~OCopServer();
25
26 QStringList channels();
27 bool isChannelRegistered(const QCString& )const;
28
29private slots:
30 void errorOnServer();// error on Server
31 void newOnServer();// accept to be taken
32 void newOnClient(int fd ); // new package received
33
34private:
35 /* replace fd with a special class in future
36 * to even work on Windoze aye aye
37 */
38 /**
39 * add a channel with a fd
40 * if the channel is not present
41 * then it'll be created
42 * if it's present we will ad the fd
43 */
44 void addChannel( const QCString& channel,
45 int fd );
46 void delChannel( const QCString& channel,
47 int fd );
48
49 /**
50 * fd was closed
51 */
52 void deregisterClient( int fd );
53
54 /**
55 * fd popped up
56 */
57 void registerClient( int fd );
58
59private:
60 void init();
61private slots:
62 void initSocket();
63private:
64 int accept();
65 void isRegistered( const QCString& channel, int );
66 void dispatch( const OCOPPacket&, int sourceFD );
67 void call( const OCOPPacket&, int sourceFD );
68 QValueList<int> clients(const QCString& channel );
69 /*
70 * All clients
71 * They include a fd and a QSocketNotifier
72 */
73 QMap<int, OCOPClient> m_clients;
74
75 /*
76 * The channels avilable
77 */
78 QMap<QCString, QValueList<int> > m_channels;
79
80 /*
81 * a notifier for our server
82 * if new stuff is arriving
83 */
84 QSocketNotifier* m_server;
85
86 /*
87 * error
88 */
89 QSocketNotifier* m_serverError;
90 int m_serverfd;
91 struct sockaddr_un m_address;
92 unsigned int m_adrlaenge;
93};
94
95#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 @@
1 TEMPLATE= app
2 CONFIG = qt warn_on debug
3 #CONFIG = qt warn_on release
4 HEADERS = ../common/ocoppacket.h ocopclient.h ocopserver.h
5 SOURCES = ../common/ocoppacket.cpp main.cpp ocopserver.cpp
6 INCLUDEPATH+= $(OPIEDIR)/include
7 DEPENDPATH+= $(OPIEDIR)/include
8 TARGET = ocopserver
9
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 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4
5#include <sys/socket.h>
6#include <sys/un.h>
7
8struct head {
9 int magic;
10 int flags;
11 int chlen;
12 int funclen;
13 int datalen;
14};
15
16int main( int argc, char* argv[] ) {
17 int fd, groesse;
18 struct sockaddr_un unix_adr;
19 struct head he;
20 char* ch = "QPE/System";
21 char* fun = "call()";
22 int test;
23 char te;
24
25
26 if( ( fd = socket(PF_UNIX, SOCK_STREAM, 0 ) ) < 0 ){
27 printf("Could not socket\n" ); return 0;
28 }
29
30 memset(&unix_adr, 0, sizeof(unix_adr ) );
31 unix_adr.sun_family = AF_UNIX;
32 strcpy(unix_adr.sun_path, "/home/ich/.opie.cop");
33 groesse = sizeof(unix_adr.sun_family) + strlen(unix_adr.sun_path);
34
35 connect(fd, (struct sockaddr*)&unix_adr, groesse );
36
37 test= 260;
38 //te = (char)test;
39 //write(fd,&test,sizeof(test));
40
41
42 he.magic = 47;
43 he.flags = 5;
44 he.chlen = strlen(ch);
45 he.funclen = strlen(fun);
46 he.datalen = 0;
47
48 for(;;){
49 write(fd,&he,sizeof(he) );
50 //write(fd,(char*)&he.magic,1);
51 write(fd,ch,strlen(ch) );
52 write(fd,fun,strlen(fun) );
53 sleep(5);
54 };
55
56
57
58}