Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ocopserver.cpp

Go to the documentation of this file.
00001 #include <errno.h>
00002 #include <signal.h>
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <unistd.h>
00006 #include <sys/socket.h>
00007 #include <sys/un.h>
00008 
00009 #include <qcstring.h>
00010 #include <qtimer.h>
00011 
00012 #include "ocopserver.h"
00013 
00014 OCopServer::OCopServer()
00015     : QObject()
00016 {
00017     setName( "ocopserver");
00018 
00019     /*
00020      * init the server
00021      */
00022     init();
00023     initSocket();
00024 }
00025 OCopServer::~OCopServer() {
00026 // socket notifiers should be deleted
00027     close(m_serverfd );
00028 }
00029 void OCopServer::init() {
00030     /*
00031      * we set SIGPIPE to SIG_IGN
00032      * to get EPIPE on reads ;)
00033      */
00034 //    qWarning("SIGPIPE to be ignored");
00035     signal(SIGPIPE,  SIG_IGN );
00036 
00037     /*
00038      * initialize some variables
00039      */
00040     m_server = 0l;
00041     m_serverError = 0l;
00042 }
00043 
00048 void OCopServer::initSocket() {
00049     /* get the home dir */
00050     QCString home( getenv("HOME") );
00051     QCString path( home + "/.opie.cop");
00052 
00053     if ( ( m_serverfd = socket( PF_UNIX, SOCK_STREAM, 0 ) ) == -1 ) {
00054         qWarning("failed to create server socket");
00055         /* try again later */
00056         QTimer::singleShot( 400, this, SLOT(initSocket() ) );
00057         return;
00058     }
00059     qWarning( "unlinking file %s", path.data() );
00060 
00061     /* unlink previous sockets */
00062     unlink( path.data() );
00063 
00064     struct sockaddr_un m_address;
00065     memset(&m_address, 0, sizeof(m_address ) );
00066     m_address.sun_family = AF_UNIX; /* unix domain socket */
00067     strcpy(m_address.sun_path, path.data() );
00068     m_adrlaenge = sizeof(m_address.sun_family) + strlen(m_address.sun_path );
00069 
00070     /* cast to make it a (sockadr*) */
00071     if (bind(m_serverfd,  (struct sockaddr*)&m_address, m_adrlaenge ) == -1 ) {
00072         qWarning("Server could not bind try again");
00073         close(m_serverfd);
00074         QTimer::singleShot(400, this, SLOT(initSocket() ) );
00075         return;
00076     }
00077 
00078     /* tell the kernel that we're listening and accepting
00079      * 5 pending connections */
00080     if (listen(m_serverfd, 5) == -1 ) {
00081         qWarning("could not listen");
00082         close(m_serverfd );
00083         QTimer::singleShot(400, this, SLOT(initSocket() ) );
00084         return;
00085     }
00086 
00087     /*
00088      * now we will create two QSocketNotifier
00089      * which will us notify on reads
00090      * and errors
00091      * we do this because they integrate
00092      * nicely into the QApplication eventloop
00093      */
00094     m_server = new QSocketNotifier(m_serverfd, QSocketNotifier::Read, this );
00095     connect( m_server, SIGNAL(activated(int) ),
00096              this, SLOT(newOnServer() ) );
00097 
00098     m_serverError = new QSocketNotifier( m_serverfd, QSocketNotifier::Exception, this);
00099     connect(m_serverError, SIGNAL(activated(int) ),
00100             this, SLOT(errorOnServer() ) );
00101 
00102     qWarning("done with registering");
00103 }
00112 void OCopServer::newOnServer() {
00113     int fd = accept();
00114     if ( fd < 0 )
00115         return;
00116 
00117     /*
00118      * we got a successful new connection
00119      * be happy
00120      * set SocketNotifier
00121      * connect it
00122      * and a OCOPClient
00123      */
00124 //    qWarning("Heureka new connection %d", fd );
00125 
00126 
00127     registerClient( fd );
00128 }
00129 int OCopServer::accept() {
00130     /*
00131      * accept it
00132      * the socket is currently blocking IIRC
00133      */
00134     return ::accept( m_serverfd,  (struct sockaddr*)&m_address, &m_adrlaenge );
00135 }
00136 void OCopServer::newOnClient( int fd ) {
00137     errno = 0;
00138     OCOPHead head;
00139     memset(&head, 0, sizeof(head) );
00140     int rea = ::read(fd, &head, sizeof(head) );
00141     //qWarning("read %d %d", rea,  errno);
00142     /*
00143      * I should get EPIPE but nothing like this happens
00144      * so if rea == 0 and we were signaled by the notifier
00145      * we close it and drop the clients...
00146      */
00147     if ( rea <= 0 ) {
00148         deregisterClient( fd );
00149         return;
00150     }
00151     /*
00152      * OCOPHead
00153      */
00154     //qWarning("data %s %d", &bug, rea );
00155 
00156     /*
00157      * Check the magic
00158      * if chcked read till EOF if magic does not match
00159      * otherwise do read
00160      *  channel
00161      * func
00162      * data into mem
00163      * and then send the OCOPPacket
00164      *
00165      */
00166     if (head.magic == 47 ) {
00167 //        qWarning("magic match");
00168         QCString channel( head.chlen+1 );
00169         QCString func( head.funclen+1 );
00170         QByteArray data ( head.datalen+1 );
00171 
00172         /*
00173          * we do not check for errors
00174          */
00175 //        qWarning("read ");
00176         int s = read(fd, channel.data(), head.chlen );
00177         s = read(fd, func.data(), head.funclen );
00178         s = read(fd, data.data(), head.datalen );
00179 //        qWarning("read");
00180 
00181         /* debug output */
00182 //        qWarning("channel %s %d", channel.data(), head.chlen );
00183 //        qWarning("func %s %d", func.data(), head.funclen );
00184         /* debug end */
00185 
00186         /*
00187          * now that we got the complete body
00188          * we need to make a package
00189          * and then we need to send it to clients
00190          * making a package is done here
00191          * dispatching it not
00192          */
00193         OCOPPacket packet( head.type, channel, func, data );
00194         dispatch( packet, fd );
00195 
00196     }else{
00197 //        qWarning("magic does not match");
00198 //        qWarning("magic %d", head.magic );
00199     }
00200 }
00201 void OCopServer::registerClient( int fd ) {
00202     if (m_clients.contains(fd) )
00203         return;
00204 
00205     QSocketNotifier* notify = new QSocketNotifier(fd, QSocketNotifier::Read, this );
00206     connect(notify, SIGNAL(activated(int) ),
00207             this, SLOT(newOnClient(int) ) );
00208     OCOPClient client;
00209     client.fd = fd;
00210     client.notify = notify;
00211     m_clients.insert( client.fd, client );
00212 //    qWarning("clients are up to %d", m_clients.count() );
00213 };
00214 void OCopServer::deregisterClient(int fd ) {
00215     QMap<int, OCOPClient>::Iterator it = m_clients.find( fd );
00216     if (it != m_clients.end() ) {
00217         /*
00218          * TIME_ME
00219          *
00220          * now delete from all channels
00221          * go through all channels
00222          * remove the fd from the list
00223          * if count becomes 0 remove the channel
00224          * otherwise replace QArray<int>
00225          */
00226         QMap<QCString, QValueList<int> >::Iterator it2;
00227     repeatIt:
00228         for ( it2 = m_channels.begin(); it2 != m_channels.end(); ++it2 ) {
00229             /*
00230              * The channel contains this fd
00231              */
00232 //            qWarning("Channel %s %d", it2.key().data(), it2.data().count() );
00233             if ( it2.data().contains( fd ) ) {
00234                 qWarning("contains");
00235                 QValueList<int> array = it2.data();
00236 
00237                 /*
00238                  * remove channel or just replace
00239                  */
00240                 if ( array.count() == 1 || array.count() == 0) {
00241 //                    qWarning("Invalidate!");
00242                     /* is the list now invalidatet? */
00243                     m_channels.remove( it2 );
00244                     /* That is the first go to of my life
00245                      * but Iterator remove( Iterator )
00246                      * does not exist
00247                      * it2 = --it2;
00248                      * does not work reliable too
00249                      * so the only way is to reiterate :(
00250                      */
00251                     goto repeatIt;
00252                 }else{
00253 //                    qWarning("removing count %d %d",fd, array.count() );
00254                     QValueList<int>::Iterator it3 = array.find( fd );
00255                     it3 = array.remove( it3 );
00256                     QCString key = it2.key().copy();
00257                     it2 = m_channels.replace( key, array );
00258                 }
00259             }
00260         } // off all channels
00261         OCOPClient client = it.data();
00262         delete client.notify;
00263         m_clients.remove(fd );
00264         close(fd );
00265     }
00266 //    qWarning("clients are now at %d", m_clients.count() );
00267 }
00272 void OCopServer::dispatch( const OCOPPacket& packet, int sourceFD ) {
00273 //    qWarning("packet.type() == %d", packet.type() );
00274     switch( packet.type() ) {
00275     case OCOPPacket::Register:
00276         registerClient(sourceFD );
00277         break;
00278     case OCOPPacket::Unregister:
00279         deregisterClient(sourceFD );
00280         break;
00281     case OCOPPacket::Call:
00282         call( packet, sourceFD );
00283         break;
00284         /* not implemented */
00285     case OCOPPacket::Method:
00286         break;
00287         /* nit implemented */
00288     case OCOPPacket::Reply:
00289         break;
00290     case OCOPPacket::RegisterChannel:
00291         addChannel( packet.channel() , sourceFD );
00292         break;
00293     case OCOPPacket::UnregisterChannel:
00294         delChannel( packet.channel(), sourceFD );
00295         break;
00296         /* not implemented */
00297     case OCOPPacket::Return:
00298         break;
00299         /* not implemented :( */
00300     case OCOPPacket::Signal:
00301         break;
00302     case OCOPPacket::IsRegistered:
00303 //        qWarning("Server:IsRegistered %s", packet.channel().data() );
00304         isRegistered( packet.channel(), sourceFD );
00305         break;
00306     };
00307 }
00308 void OCopServer::errorOnServer() {
00309     /*
00310      * something is wrong on the server socket?
00311      * what should we do?
00312      * FIXME
00313      */
00314 }
00315 QStringList OCopServer::channels() {
00316     QStringList list;
00317     {
00318         QMap<QCString, QValueList<int> >::Iterator it;
00319         for (it = m_channels.begin(); it != m_channels.end(); ++it ) {
00320             list << it.key();
00321         };
00322     }
00323     return list;
00324 }
00325 bool OCopServer::isChannelRegistered( const QCString& chan ) const{
00326     return m_channels.contains( chan );
00327 }
00328 void OCopServer::addChannel( const QCString& channel,
00329                              int fd ) {
00330     QMap<QCString, QValueList<int> >::Iterator it;
00331     it = m_channels.find( channel );
00332     if ( it != m_channels.end() ) {
00333         /* could be empty */
00334         QValueList<int> list = it.data();
00335         list.append( fd );
00336         qWarning("Server:count is now in addChannel %d %s", list.count(), channel.data() );
00337         it = m_channels.replace( channel, list );
00338     }else {
00339         QValueList<int> ints;
00340         ints.append( fd );
00341         m_channels.insert( channel, ints );
00342     }
00343 };
00344 void OCopServer::delChannel( const QCString& channel,
00345                              int fd ) {
00346 //    qWarning("remove %s, %d", channel.data(), fd );
00347     if (!m_channels.contains( channel ) )
00348         return;
00349 
00350     QMap<QCString, QValueList<int> >::Iterator it;
00351     it = m_channels.find( channel );
00352 
00353     if ( it.data().contains(fd) ) {
00354         QValueList<int> ints = it.data();
00355         if ( ints.count() == 1  )
00356             m_channels.remove( channel );
00357         else{
00358             QValueList<int> ints = it.data();
00359             QValueList<int>::Iterator rem = ints.find( fd );
00360             rem = ints.remove( rem );
00361             QCString str = it.key().copy();
00362             m_channels.replace( str, ints );
00363         }
00364 //        qWarning(" channel count is now %d", ints.count() );
00365     }
00366 }
00367 void OCopServer::isRegistered( const QCString& channel, int fd) {
00368 //    qWarning("Server:isRegistered %s", channel.data() );
00369     OCOPHead head;
00370     QCString func(2);
00371 
00372     memset(&head, 0, sizeof(head ) );
00373     head.magic = 47;
00374     head.type = OCOPPacket::IsRegistered;
00375     head.chlen = channel.size();
00376     head.funclen = func.size();
00377     head.datalen = 0;
00378 
00379     if ( isChannelRegistered( channel ) ) {
00380         //is registered
00381         func[0] = 1;
00382 //      qWarning("Server:Channel is Registered %d", head.chlen);
00383     }else{
00384         func[0] = 0;
00385 //      qWarning("Server:Channel is NotRegistered");
00386     }
00387 
00393     write(fd, &head, sizeof(head) );
00394     write(fd, channel.data(), channel.size() );
00395     write(fd, func.data(), func.size() );
00396 }
00397 QValueList<int> OCopServer::clients( const QCString& channel ) {
00398     return m_channels[channel];
00399 }
00400 void OCopServer::call( const OCOPPacket& p, int ) {
00401     QValueList<int> cli = clients( p.channel() );
00402     QValueList<int>::Iterator it;
00403 
00404     OCOPHead head = p.head();
00405     for (it = cli.begin(); it != cli.end(); ++it ) {
00406 //        qWarning("Server:calling %d %s %s", (*it), p.channel().data(), p.header().data() );
00407         write( (*it), &head, sizeof(head ) );
00408         /* expl. shared! */
00409         write( (*it), p.channel().data(), p.channel().size() );
00410         write( (*it), p.header().data(), p.header().size() );
00411         write( (*it), p.content().data(), p.content().size() );
00412     };
00413 }

Generated on Sat Nov 5 16:18:35 2005 for OPIE by  doxygen 1.4.2