| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kbufferedsocket.cpp

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

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:01 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003