• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

k3bufferedsocket.cpp

Go to the documentation of this file.
00001 /*  -*- C++ -*-
00002  *  Copyright (C) 2003-2005 Thiago Macieira <thiago@kde.org>
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 "k3bufferedsocket.h"
00026 
00027 #include <config.h>
00028 #include <config-network.h>
00029 
00030 #include <QMutex>
00031 #include <QTimer>
00032 
00033 #include "k3socketdevice.h"
00034 #include "k3socketaddress.h"
00035 #include "k3socketbuffer_p.h"
00036 
00037 using namespace KNetwork;
00038 using namespace KNetwork::Internal;
00039 
00040 class KNetwork::KBufferedSocketPrivate
00041 {
00042 public:
00043   mutable KSocketBuffer *input, *output;
00044 
00045   KBufferedSocketPrivate()
00046   {
00047     input = 0L;
00048     output = 0L;
00049   }
00050 };
00051 
00052 KBufferedSocket::KBufferedSocket(const QString& host, const QString& service,
00053                  QObject *parent)
00054   : KStreamSocket(host, service, parent),
00055     d(new KBufferedSocketPrivate)
00056 {
00057   setInputBuffering(true);
00058   setOutputBuffering(true);
00059 }
00060 
00061 KBufferedSocket::~KBufferedSocket()
00062 {
00063   closeNow();
00064   delete d->input;
00065   delete d->output;
00066   delete d;
00067 }
00068 
00069 void KBufferedSocket::setSocketDevice(KSocketDevice* device)
00070 {
00071   KStreamSocket::setSocketDevice(device);
00072   device->setBlocking(false);
00073   KActiveSocketBase::open(openMode() & ~Unbuffered);
00074 }
00075 
00076 bool KBufferedSocket::setSocketOptions(int opts)
00077 {
00078   if (opts == Blocking)
00079     return false;
00080 
00081   opts &= ~Blocking;
00082   return KStreamSocket::setSocketOptions(opts);
00083 }
00084 
00085 void KBufferedSocket::close()
00086 {
00087   if (!d->output || d->output->isEmpty())
00088     closeNow();
00089   else
00090     {
00091       setState(Closing);
00092       QSocketNotifier *n = socketDevice()->readNotifier();
00093       if (n)
00094     n->setEnabled(false);
00095       emit stateChanged(Closing);
00096     }
00097 }
00098 
00099 qint64 KBufferedSocket::bytesAvailable() const
00100 {
00101   if (!d->input)
00102     return KStreamSocket::bytesAvailable();
00103 
00104   return d->input->length();
00105 }
00106 
00107 qint64 KBufferedSocket::waitForMore(int msecs, bool *timeout)
00108 {
00109   qint64 retval = KStreamSocket::waitForMore(msecs, timeout);
00110   if (d->input)
00111     {
00112       resetError();
00113       slotReadActivity();
00114       return bytesAvailable();
00115     }
00116   return retval;
00117 }
00118 
00119 qint64 KBufferedSocket::readData(char *data, qint64 maxlen, KSocketAddress* from)
00120 {
00121   if (from)
00122     *from = peerAddress();
00123   if (d->input)
00124     {
00125       if (d->input->isEmpty())
00126       {
00127         return 0;
00128       }
00129       resetError();
00130       return d->input->consumeBuffer(data, maxlen);
00131     }
00132   return KStreamSocket::readData(data, maxlen, 0L);
00133 }
00134 
00135 qint64 KBufferedSocket::peekData(char *data, qint64 maxlen, KSocketAddress* from)
00136 {
00137   if (from)
00138     *from = peerAddress();
00139   if (d->input)
00140     {
00141       if (d->input->isEmpty())
00142       {
00143         return 0;
00144       }
00145       resetError();
00146       return d->input->consumeBuffer(data, maxlen, false);
00147     }
00148   return KStreamSocket::peekData(data, maxlen, 0L);
00149 }
00150 
00151 qint64 KBufferedSocket::writeData(const char *data, qint64 len,
00152                    const KSocketAddress*)
00153 {
00154   // ignore the third parameter
00155   if (state() != Connected)
00156     {
00157       // cannot write now!
00158       setError(NotConnected);
00159       return -1;
00160     }
00161 
00162   if (d->output)
00163     {
00164       if (d->output->isFull())
00165     {
00166       setError(WouldBlock);
00167       emit gotError(WouldBlock);
00168       return -1;
00169     }
00170       resetError();
00171 
00172       // enable notifier to send data
00173       QSocketNotifier *n = socketDevice()->writeNotifier();
00174       if (n)
00175     n->setEnabled(true);
00176 
00177       return d->output->feedBuffer(data, len);
00178     }
00179 
00180   return KStreamSocket::writeData(data, len, 0L);
00181 }
00182 
00183 void KBufferedSocket::enableRead(bool enable)
00184 {
00185   KStreamSocket::enableRead(enable);
00186   if (!enable && d->input)
00187     {
00188       // reenable it
00189       QSocketNotifier *n = socketDevice()->readNotifier();
00190       if (n)
00191     n->setEnabled(true);
00192     }
00193 
00194   if (enable && state() != Connected && d->input && !d->input->isEmpty())
00195     // this means the buffer is still dirty
00196     // allow the signal to be emitted
00197     QTimer::singleShot(0, this, SLOT(slotReadActivity()));
00198 }
00199 
00200 void KBufferedSocket::enableWrite(bool enable)
00201 {
00202   KStreamSocket::enableWrite(enable);
00203   if (!enable && d->output && !d->output->isEmpty())
00204     {
00205       // reenable it
00206       QSocketNotifier *n = socketDevice()->writeNotifier();
00207       if (n)
00208     n->setEnabled(true);
00209     }
00210 }
00211 
00212 void KBufferedSocket::stateChanging(SocketState newState)
00213 {
00214   if (newState == Connecting || newState == Connected)
00215     {
00216       // we're going to connect
00217       // make sure the buffers are clean
00218       if (d->input)
00219     d->input->clear();
00220       if (d->output)
00221     d->output->clear();
00222 
00223       // also, turn on notifiers
00224       enableRead(emitsReadyRead());
00225       enableWrite(emitsReadyWrite());
00226     }
00227   KStreamSocket::stateChanging(newState);
00228 }
00229 
00230 void KBufferedSocket::setInputBuffering(bool enable)
00231 {
00232   QMutexLocker locker(mutex());
00233   if (!enable)
00234     {
00235       delete d->input;
00236       d->input = 0L;
00237     }
00238   else if (d->input == 0L)
00239     {
00240       d->input = new KSocketBuffer;
00241     }
00242 }
00243 
00244 void KBufferedSocket::setOutputBuffering(bool enable)
00245 {
00246   QMutexLocker locker(mutex());
00247   if (!enable)
00248     {
00249       delete d->output;
00250       d->output = 0L;
00251     }
00252   else if (d->output == 0L)
00253     {
00254       d->output = new KSocketBuffer;
00255     }
00256 }
00257 
00258 qint64 KBufferedSocket::bytesToWrite() const
00259 {
00260   if (!d->output)
00261     return 0;
00262 
00263   return d->output->length();
00264 }
00265 
00266 void KBufferedSocket::closeNow()
00267 {
00268   KStreamSocket::close();
00269   if (d->output)
00270     d->output->clear();
00271 }
00272 
00273 bool KBufferedSocket::canReadLine() const
00274 {
00275   if (!d->input)
00276     return false;
00277 
00278   return d->input->canReadLine();
00279 }
00280 
00281 qint64 KBufferedSocket::readLineData(char* data, qint64 maxSize)
00282 {
00283   return d->input->readLine(data, maxSize);
00284 }
00285 
00286 void KBufferedSocket::waitForConnect()
00287 {
00288   if (state() != Connecting)
00289     return;         // nothing to be waited on
00290 
00291   KStreamSocket::setSocketOptions(socketOptions() | Blocking);
00292   connectionEvent();
00293   KStreamSocket::setSocketOptions(socketOptions() & ~Blocking);
00294 }
00295 
00296 void KBufferedSocket::slotReadActivity()
00297 {
00298   if (d->input && state() == Connected)
00299     {
00300       mutex()->lock();
00301       qint64 len = d->input->receiveFrom(socketDevice());
00302 
00303       if (len == -1)
00304     {
00305       if (socketDevice()->error() != WouldBlock)
00306         {
00307           // nope, another error!
00308           copyError();
00309           mutex()->unlock();
00310           emit gotError(error());
00311           closeNow();   // emits closed
00312           return;
00313         }
00314     }
00315       else if (len == 0)
00316     {
00317       // remotely closed
00318       setError(RemotelyDisconnected);
00319       mutex()->unlock();
00320       emit gotError(error());
00321       closeNow();       // emits closed
00322       return;
00323     }
00324 
00325       // no error
00326       mutex()->unlock();
00327     }
00328 
00329   if (state() == Connected)
00330     KStreamSocket::slotReadActivity(); // this emits readyRead
00331   else if (emitsReadyRead())    // state() != Connected
00332     {
00333       if (d->input && !d->input->isEmpty())
00334     {
00335       // buffer isn't empty
00336       // keep emitting signals till it is
00337       QTimer::singleShot(0, this, SLOT(slotReadActivity()));
00338       emit readyRead();
00339     }
00340     }
00341 }
00342 
00343 void KBufferedSocket::slotWriteActivity()
00344 {
00345   if (d->output && !d->output->isEmpty() &&
00346       (state() == Connected || state() == Closing))
00347     {
00348       mutex()->lock();
00349       qint64 len = d->output->sendTo(socketDevice());
00350 
00351       if (len == -1)
00352     {
00353       if (socketDevice()->error() != WouldBlock)
00354         {
00355           // nope, another error!
00356           copyError();
00357           mutex()->unlock();
00358           emit gotError(error());
00359           closeNow();
00360           return;
00361         }
00362     }
00363       else if (len == 0)
00364     {
00365       // remotely closed
00366       setError(RemotelyDisconnected);
00367       mutex()->unlock();
00368       emit gotError(error());
00369       closeNow();
00370       return;
00371     }
00372 
00373       if (d->output->isEmpty())
00374     // deactivate the notifier until we have something to send
00375     // writeNotifier can't return NULL here
00376     socketDevice()->writeNotifier()->setEnabled(false);
00377 
00378       mutex()->unlock();
00379       emit bytesWritten(len);
00380     }
00381 
00382   if (state() != Closing)
00383     KStreamSocket::slotWriteActivity();
00384   else if (d->output && d->output->isEmpty() && state() == Closing)
00385     {
00386       KStreamSocket::close();   // finished sending data
00387     }
00388 }
00389 
00390 #include "k3bufferedsocket.moc"

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal