kdecore Library API Documentation

kbufferedsocket.cpp

00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net>
00003  *
00004  *
00005  *  Permission is hereby granted, free of charge, to any person obtaining
00006  *  a copy of this software and associated documentation files (the
00007  *  "Software"), to deal in the Software without restriction, including
00008  *  without limitation the rights to use, copy, modify, merge, publish,
00009  *  distribute, sublicense, and/or sell copies of the Software, and to
00010  *  permit persons to whom the Software is furnished to do so, subject to
00011  *  the following conditions:
00012  *
00013  *  The above copyright notice and this permission notice shall be included
00014  *  in all copies or substantial portions of the Software.
00015  *
00016  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00017  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00018  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00019  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00020  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00021  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00022  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include <qmutex.h>
00028 #include <qtimer.h>
00029 
00030 #include "ksocketdevice.h"
00031 #include "ksocketaddress.h"
00032 #include "ksocketbuffer_p.h"
00033 #include "kbufferedsocket.h"
00034 
00035 using namespace KNetwork;
00036 using namespace KNetwork::Internal;
00037 
00038 class KNetwork::KBufferedSocketPrivate
00039 {
00040 public:
00041   mutable KSocketBuffer *input, *output;
00042 
00043   KBufferedSocketPrivate()
00044   {
00045     input = 0L;
00046     output = 0L;
00047   }
00048 };
00049 
00050 KBufferedSocket::KBufferedSocket(const QString& host, const QString& service,
00051                  QObject *parent, const char *name)
00052   : KStreamSocket(host, service, parent, name),
00053     d(new KBufferedSocketPrivate)
00054 {
00055   setBlocking(false);
00056   setInputBuffering(true);
00057   setOutputBuffering(true);
00058 }
00059 
00060 KBufferedSocket::~KBufferedSocket()
00061 {
00062   closeNow();
00063   delete d->input;
00064   delete d->output;
00065   delete d;
00066 }
00067 
00068 void KBufferedSocket::setSocketDevice(KSocketDevice* device)
00069 {
00070   KStreamSocket::setSocketDevice(device);
00071   device->setBlocking(false);
00072 }
00073 
00074 bool KBufferedSocket::setSocketOptions(int opts)
00075 {
00076   if (opts == Blocking)
00077     return false;
00078 
00079   opts &= ~Blocking;
00080   return KStreamSocket::setSocketOptions(opts);
00081 }
00082 
00083 void KBufferedSocket::close()
00084 {
00085   if (!d->output || d->output->isEmpty())
00086     closeNow();
00087   else
00088     {
00089       setState(Closing);
00090       QSocketNotifier *n = socketDevice()->readNotifier();
00091       if (n)
00092     n->setEnabled(false);
00093       emit stateChanged(Closing);
00094     }
00095 }
00096 
00097 Q_LONG KBufferedSocket::bytesAvailable() const
00098 {
00099   if (!d->input)
00100     return KStreamSocket::bytesAvailable();
00101 
00102   return d->input->length();
00103 }
00104 
00105 Q_LONG KBufferedSocket::waitForMore(int msecs, bool *timeout)
00106 {
00107   Q_LONG retval = KStreamSocket::waitForMore(msecs, timeout);
00108   if (d->input)
00109     {
00110       resetError();
00111       slotReadActivity();
00112       return bytesAvailable();
00113     }
00114   return retval;
00115 }
00116 
00117 Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen)
00118 {
00119   if (d->input)
00120     {
00121       if (d->input->isEmpty())
00122     {
00123       setError(IO_ReadError, WouldBlock);
00124       emit gotError(WouldBlock);
00125       return -1;
00126     }
00127       resetError();
00128       return d->input->consumeBuffer(data, maxlen);
00129     }
00130   return KStreamSocket::readBlock(data, maxlen);
00131 }
00132 
00133 Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
00134 {
00135   from = peerAddress();
00136   return readBlock(data, maxlen);
00137 }
00138 
00139 Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen)
00140 {
00141   if (d->input)
00142     {
00143       if (d->input->isEmpty())
00144     {
00145       setError(IO_ReadError, WouldBlock);
00146       emit gotError(WouldBlock);
00147       return -1;
00148     }
00149       resetError();
00150       return d->input->consumeBuffer(data, maxlen, false);
00151     }
00152   return KStreamSocket::peekBlock(data, maxlen);
00153 }
00154 
00155 Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
00156 {
00157   from = peerAddress();
00158   return peekBlock(data, maxlen);
00159 }
00160 
00161 Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG len)
00162 {
00163   if (state() != Connected)
00164     {
00165       // cannot write now!
00166       setError(IO_WriteError, NotConnected);
00167       return -1;
00168     }
00169 
00170   if (d->output)
00171     {
00172       if (d->output->isFull())
00173     {
00174       setError(IO_WriteError, WouldBlock);
00175       emit gotError(WouldBlock);
00176       return -1;
00177     }
00178       resetError();
00179 
00180       // enable notifier to send data
00181       QSocketNotifier *n = socketDevice()->writeNotifier();
00182       if (n)
00183     n->setEnabled(true);
00184 
00185       return d->output->feedBuffer(data, len);
00186     }
00187 
00188   return KStreamSocket::writeBlock(data, len);
00189 }
00190 
00191 Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG maxlen,
00192                    const KSocketAddress&)
00193 {
00194   // ignore the third parameter
00195   return writeBlock(data, maxlen);
00196 }
00197 
00198 void KBufferedSocket::enableRead(bool enable)
00199 {
00200   KStreamSocket::enableRead(enable);
00201   if (!enable && d->input)
00202     {
00203       // reenable it
00204       QSocketNotifier *n = socketDevice()->readNotifier();
00205       if (n)
00206     n->setEnabled(true);
00207     }
00208 
00209   if (enable && state() != Connected && d->input && !d->input->isEmpty())
00210     // this means the buffer is still dirty
00211     // allow the signal to be emitted
00212     QTimer::singleShot(0, this, SLOT(slotReadActivity()));
00213 }
00214 
00215 void KBufferedSocket::enableWrite(bool enable)
00216 {
00217   KStreamSocket::enableWrite(enable);
00218   if (!enable && d->output && !d->output->isEmpty())
00219     {
00220       // reenable it
00221       QSocketNotifier *n = socketDevice()->writeNotifier();
00222       if (n)
00223     n->setEnabled(true);
00224     }
00225 }
00226 
00227 void KBufferedSocket::stateChanging(SocketState newState)
00228 {
00229   if (newState == Connecting || newState == Connected)
00230     {
00231       // we're going to connect
00232       // make sure the buffers are clean
00233       if (d->input)
00234     d->input->clear();
00235       if (d->output)
00236     d->output->clear();
00237 
00238       // also, turn on notifiers
00239       enableRead(emitsReadyRead());
00240       enableWrite(emitsReadyWrite());
00241     }
00242   KStreamSocket::stateChanging(newState);
00243 }
00244 
00245 void KBufferedSocket::setInputBuffering(bool enable)
00246 {
00247   QMutexLocker locker(mutex());
00248   if (!enable)
00249     {
00250       delete d->input;
00251       d->input = 0L;
00252     }
00253   else if (d->input == 0L)
00254     {
00255       d->input = new KSocketBuffer;
00256     }
00257 }
00258 
00259 KIOBufferBase* KBufferedSocket::inputBuffer()
00260 {
00261   return d->input;
00262 }
00263 
00264 void KBufferedSocket::setOutputBuffering(bool enable)
00265 {
00266   QMutexLocker locker(mutex());
00267   if (!enable)
00268     {
00269       delete d->output;
00270       d->output = 0L;
00271     }
00272   else if (d->output == 0L)
00273     {
00274       d->output = new KSocketBuffer;
00275     }
00276 }
00277 
00278 KIOBufferBase* KBufferedSocket::outputBuffer()
00279 {
00280   return d->output;
00281 }
00282 
00283 Q_ULONG KBufferedSocket::bytesToWrite() const
00284 {
00285   if (!d->output)
00286     return 0;
00287 
00288   return d->output->length();
00289 }
00290 
00291 void KBufferedSocket::closeNow()
00292 {
00293   KStreamSocket::close();
00294 }
00295 
00296 bool KBufferedSocket::canReadLine() const
00297 {
00298   if (!d->input)
00299     return false;
00300 
00301   return d->input->canReadLine();
00302 }
00303 
00304 QCString KBufferedSocket::readLine()
00305 {
00306   return d->input->readLine();
00307 }
00308 
00309 void KBufferedSocket::slotReadActivity()
00310 {
00311   if (d->input && state() == Connected)
00312     {
00313       mutex()->lock();
00314       Q_LONG len = d->input->receiveFrom(socketDevice());
00315 
00316       if (len == -1)
00317     {
00318       if (socketDevice()->error() != WouldBlock)
00319         {
00320           // nope, another error!
00321           copyError();
00322           mutex()->unlock();
00323           closeNow();   // emits closed
00324           return;
00325         }
00326     }
00327       else if (len == 0)
00328     {
00329       // remotely closed
00330       resetError();
00331       mutex()->unlock();
00332       closeNow();       // emits closed
00333       return;
00334     }
00335 
00336       // no error
00337       mutex()->unlock();
00338     }
00339 
00340   if (state() == Connected)
00341     KStreamSocket::slotReadActivity(); // this emits readyRead
00342   else if (emitsReadyRead())    // state() != Connected
00343     {
00344       if (d->input && !d->input->isEmpty())
00345     {
00346       // buffer isn't empty
00347       // keep emitting signals till it is
00348       QTimer::singleShot(0, this, SLOT(slotReadActivity()));
00349       emit readyRead();
00350     }
00351     }
00352 }
00353 
00354 void KBufferedSocket::slotWriteActivity()
00355 {
00356   if (d->output && !d->output->isEmpty() &&
00357       (state() == Connected || state() == Closing))
00358     {
00359       mutex()->lock();
00360       Q_LONG len = d->output->sendTo(socketDevice());
00361 
00362       if (len == -1)
00363     {
00364       if (socketDevice()->error() != WouldBlock)
00365         {
00366           // nope, another error!
00367           copyError();
00368           mutex()->unlock();
00369           closeNow();
00370           return;
00371         }
00372     }
00373       else if (len == 0)
00374     {
00375       // remotely closed
00376       resetError();
00377       mutex()->unlock();
00378       closeNow();
00379       return;
00380     }
00381 
00382       if (d->output->isEmpty())
00383     // deactivate the notifier until we have something to send
00384     // writeNotifier can't return NULL here
00385     socketDevice()->writeNotifier()->setEnabled(false);
00386 
00387       mutex()->unlock();
00388       emit bytesWritten(len);
00389     }
00390 
00391   if (state() != Closing)
00392     KStreamSocket::slotWriteActivity();
00393   else if (d->output && d->output->isEmpty() && state() == Closing)
00394     {
00395       KStreamSocket::close();   // finished sending data
00396     }
00397 }
00398 
00399 #include "kbufferedsocket.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Nov 27 13:41:07 2004 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003