kbufferedsocket.cpp
/* -*- C++ -*-
* Copyright (C) 2003-2005 Thiago Macieira <thiago.macieira@kdemail.net>
*
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
#include <qmutex.h>
#include <qtimer.h>
#include "ksocketdevice.h"
#include "ksocketaddress.h"
#include "ksocketbuffer_p.h"
#include "kbufferedsocket.h"
using namespace KNetwork;
using namespace KNetwork::Internal;
class KNetwork::KBufferedSocketPrivate
{
public:
mutable KSocketBuffer *input, *output;
KBufferedSocketPrivate()
{
input = 0L;
output = 0L;
}
};
KBufferedSocket::KBufferedSocket(const QString& host, const QString& service,
QObject *parent, const char *name)
: KStreamSocket(host, service, parent, name),
d(new KBufferedSocketPrivate)
{
setInputBuffering(true);
setOutputBuffering(true);
}
KBufferedSocket::~KBufferedSocket()
{
closeNow();
delete d->input;
delete d->output;
delete d;
}
void KBufferedSocket::setSocketDevice(KSocketDevice* device)
{
KStreamSocket::setSocketDevice(device);
device->setBlocking(false);
}
bool KBufferedSocket::setSocketOptions(int opts)
{
if (opts == Blocking)
return false;
opts &= ~Blocking;
return KStreamSocket::setSocketOptions(opts);
}
void KBufferedSocket::close()
{
if (!d->output || d->output->isEmpty())
closeNow();
else
{
setState(Closing);
QSocketNotifier *n = socketDevice()->readNotifier();
if (n)
n->setEnabled(false);
emit stateChanged(Closing);
}
}
Q_LONG KBufferedSocket::bytesAvailable() const
{
if (!d->input)
return KStreamSocket::bytesAvailable();
return d->input->length();
}
Q_LONG KBufferedSocket::waitForMore(int msecs, bool *timeout)
{
Q_LONG retval = KStreamSocket::waitForMore(msecs, timeout);
if (d->input)
{
resetError();
slotReadActivity();
return bytesAvailable();
}
return retval;
}
Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen)
{
if (d->input)
{
if (d->input->isEmpty())
{
setError(IO_ReadError, WouldBlock);
emit gotError(WouldBlock);
return -1;
}
resetError();
return d->input->consumeBuffer(data, maxlen);
}
return KStreamSocket::readBlock(data, maxlen);
}
Q_LONG KBufferedSocket::readBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
{
from = peerAddress();
return readBlock(data, maxlen);
}
Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen)
{
if (d->input)
{
if (d->input->isEmpty())
{
setError(IO_ReadError, WouldBlock);
emit gotError(WouldBlock);
return -1;
}
resetError();
return d->input->consumeBuffer(data, maxlen, false);
}
return KStreamSocket::peekBlock(data, maxlen);
}
Q_LONG KBufferedSocket::peekBlock(char *data, Q_ULONG maxlen, KSocketAddress& from)
{
from = peerAddress();
return peekBlock(data, maxlen);
}
Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG len)
{
if (state() != Connected)
{
// cannot write now!
setError(IO_WriteError, NotConnected);
return -1;
}
if (d->output)
{
if (d->output->isFull())
{
setError(IO_WriteError, WouldBlock);
emit gotError(WouldBlock);
return -1;
}
resetError();
// enable notifier to send data
QSocketNotifier *n = socketDevice()->writeNotifier();
if (n)
n->setEnabled(true);
return d->output->feedBuffer(data, len);
}
return KStreamSocket::writeBlock(data, len);
}
Q_LONG KBufferedSocket::writeBlock(const char *data, Q_ULONG maxlen,
const KSocketAddress&)
{
// ignore the third parameter
return writeBlock(data, maxlen);
}
void KBufferedSocket::enableRead(bool enable)
{
KStreamSocket::enableRead(enable);
if (!enable && d->input)
{
// reenable it
QSocketNotifier *n = socketDevice()->readNotifier();
if (n)
n->setEnabled(true);
}
if (enable && state() != Connected && d->input && !d->input->isEmpty())
// this means the buffer is still dirty
// allow the signal to be emitted
QTimer::singleShot(0, this, SLOT(slotReadActivity()));
}
void KBufferedSocket::enableWrite(bool enable)
{
KStreamSocket::enableWrite(enable);
if (!enable && d->output && !d->output->isEmpty())
{
// reenable it
QSocketNotifier *n = socketDevice()->writeNotifier();
if (n)
n->setEnabled(true);
}
}
void KBufferedSocket::stateChanging(SocketState newState)
{
if (newState == Connecting || newState == Connected)
{
// we're going to connect
// make sure the buffers are clean
if (d->input)
d->input->clear();
if (d->output)
d->output->clear();
// also, turn on notifiers
enableRead(emitsReadyRead());
enableWrite(emitsReadyWrite());
}
KStreamSocket::stateChanging(newState);
}
void KBufferedSocket::setInputBuffering(bool enable)
{
QMutexLocker locker(mutex());
if (!enable)
{
delete d->input;
d->input = 0L;
}
else if (d->input == 0L)
{
d->input = new KSocketBuffer;
}
}
KIOBufferBase* KBufferedSocket::inputBuffer()
{
return d->input;
}
void KBufferedSocket::setOutputBuffering(bool enable)
{
QMutexLocker locker(mutex());
if (!enable)
{
delete d->output;
d->output = 0L;
}
else if (d->output == 0L)
{
d->output = new KSocketBuffer;
}
}
KIOBufferBase* KBufferedSocket::outputBuffer()
{
return d->output;
}
Q_ULONG KBufferedSocket::bytesToWrite() const
{
if (!d->output)
return 0;
return d->output->length();
}
void KBufferedSocket::closeNow()
{
KStreamSocket::close();
if (d->output)
d->output->clear();
}
bool KBufferedSocket::canReadLine() const
{
if (!d->input)
return false;
return d->input->canReadLine();
}
QCString KBufferedSocket::readLine()
{
return d->input->readLine();
}
void KBufferedSocket::waitForConnect()
{
if (state() != Connecting)
return; // nothing to be waited on
KStreamSocket::setSocketOptions(socketOptions() | Blocking);
connectionEvent();
KStreamSocket::setSocketOptions(socketOptions() & ~Blocking);
}
void KBufferedSocket::slotReadActivity()
{
if (d->input && state() == Connected)
{
mutex()->lock();
Q_LONG len = d->input->receiveFrom(socketDevice());
if (len == -1)
{
if (socketDevice()->error() != WouldBlock)
{
// nope, another error!
copyError();
mutex()->unlock();
emit gotError(error());
closeNow(); // emits closed
return;
}
}
else if (len == 0)
{
// remotely closed
setError(IO_ReadError, RemotelyDisconnected);
mutex()->unlock();
emit gotError(error());
closeNow(); // emits closed
return;
}
// no error
mutex()->unlock();
}
if (state() == Connected)
KStreamSocket::slotReadActivity(); // this emits readyRead
else if (emitsReadyRead()) // state() != Connected
{
if (d->input && !d->input->isEmpty())
{
// buffer isn't empty
// keep emitting signals till it is
QTimer::singleShot(0, this, SLOT(slotReadActivity()));
emit readyRead();
}
}
}
void KBufferedSocket::slotWriteActivity()
{
if (d->output && !d->output->isEmpty() &&
(state() == Connected || state() == Closing))
{
mutex()->lock();
Q_LONG len = d->output->sendTo(socketDevice());
if (len == -1)
{
if (socketDevice()->error() != WouldBlock)
{
// nope, another error!
copyError();
mutex()->unlock();
emit gotError(error());
closeNow();
return;
}
}
else if (len == 0)
{
// remotely closed
setError(IO_ReadError, RemotelyDisconnected);
mutex()->unlock();
emit gotError(error());
closeNow();
return;
}
if (d->output->isEmpty())
// deactivate the notifier until we have something to send
// writeNotifier can't return NULL here
socketDevice()->writeNotifier()->setEnabled(false);
mutex()->unlock();
emit bytesWritten(len);
}
if (state() != Closing)
KStreamSocket::slotWriteActivity();
else if (d->output && d->output->isEmpty() && state() == Closing)
{
KStreamSocket::close(); // finished sending data
}
}
#include "kbufferedsocket.moc"
KNetwork::KSocketBase::socketDevice
KSocketDevice * socketDevice() const
Retrieves the socket implementation used on this socket.
Definition: ksocketbase.cpp:116
KNetwork::KStreamSocket
Simple stream socket.
Definition: kstreamsocket.h:97
KNetwork::KClientSocketBase::state
SocketState state() const
Returns the current state for this socket.
Definition: kclientsocketbase.cpp:64
KNetwork::KBufferedSocket::close
virtual void close()
Closes the socket for new data, but allow data that had been buffered for output with writeBlock to b...
Definition: kbufferedsocket.cpp:82
KNetwork::KBufferedSocket::KBufferedSocket
KBufferedSocket(const QString &node=QString::null, const QString &service=QString::null, QObject *parent=0L, const char *name=0L)
Default constructor.
Definition: kbufferedsocket.cpp:50
KNetwork::KBufferedSocket::bytesAvailable
virtual Q_LONG bytesAvailable() const
Make use of the buffers.
Definition: kbufferedsocket.cpp:96
KNetwork::KBufferedSocket::slotReadActivity
virtual void slotReadActivity()
Slot called when there's read activity.
Definition: kbufferedsocket.cpp:320
KNetwork::KClientSocketBase::waitForMore
virtual Q_LONG waitForMore(int msecs, bool *timeout=0L)
Waits for more data.
Definition: kclientsocketbase.cpp:289
KNetwork::KClientSocketBase::writeBlock
virtual Q_LONG writeBlock(const char *data, Q_ULONG len)
Writes data to the socket.
Definition: kclientsocketbase.cpp:349
KNetwork::KBufferedSocket::setSocketDevice
virtual void setSocketDevice(KSocketDevice *device)
Be sure to catch new devices.
Definition: kbufferedsocket.cpp:67
KNetwork::KBufferedSocket::setSocketOptions
virtual bool setSocketOptions(int opts)
Buffered sockets can only operate in non-blocking mode.
Definition: kbufferedsocket.cpp:73
KNetwork::KActiveSocketBase::resetError
void resetError()
Resets the socket error code and the I/O Device's status.
Definition: ksocketbase.cpp:315
KNetwork::KSocketDevice::writeNotifier
QSocketNotifier * writeNotifier() const
Returns a socket notifier for output on this socket.
Definition: ksocketdevice.cpp:627
KNetwork::KBufferedSocket::peekBlock
virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen)
Peeks data from the socket.
Definition: kbufferedsocket.cpp:138
KNetwork::KBufferedSocket::canReadLine
bool canReadLine() const
Returns true if a line can be read with readLine.
Definition: kbufferedsocket.cpp:297
KNetwork::KClientSocketBase::slotReadActivity
virtual void slotReadActivity()
This slot is connected to the read notifier's signal meaning the socket can read more data...
Definition: kclientsocketbase.cpp:413
KNetwork::KSocketBase::error
SocketError error() const
Retrieves the socket error code.
Definition: ksocketbase.cpp:160
KNetwork::KBufferedSocket::bytesToWrite
virtual Q_ULONG bytesToWrite() const
Returns the length of the output buffer.
Definition: kbufferedsocket.cpp:282
KNetwork::KBufferedSocket::writeBlock
virtual Q_LONG writeBlock(const char *data, Q_ULONG len)
Writes data to the socket.
Definition: kbufferedsocket.cpp:160
KNetwork::KSocketAddress
A generic socket address.
Definition: ksocketaddress.h:423
KNetwork::KClientSocketBase::gotError
void gotError(int code)
This signal is emitted when this object finds an error.
KNetwork::KClientSocketBase::setSocketOptions
virtual bool setSocketOptions(int opts)
Sets the socket options.
Definition: kclientsocketbase.cpp:75
KNetwork::KSocketDevice::readNotifier
QSocketNotifier * readNotifier() const
Returns a socket notifier for input on this socket.
Definition: ksocketdevice.cpp:609
KNetwork::KBufferedSocket::closeNow
virtual void closeNow()
Closes the socket and discards any output data that had been buffered with writeBlock but that had no...
Definition: kbufferedsocket.cpp:290
KNetwork::KBufferedSocket::bytesWritten
void bytesWritten(int bytes)
This signal is emitted whenever data is written.
KNetwork::KClientSocketBase::copyError
void copyError()
Convenience function to set this object's error code to match that of the socket device.
Definition: kclientsocketbase.cpp:472
KNetwork::KClientSocketBase::peerAddress
virtual KSocketAddress peerAddress() const
Returns the peer socket address.
Definition: kclientsocketbase.cpp:378
KNetwork::KClientSocketBase::peekBlock
virtual Q_LONG peekBlock(char *data, Q_ULONG maxlen)
Peeks data from the socket.
Definition: kclientsocketbase.cpp:325
KNetwork::KSocketBase::mutex
QMutex * mutex() const
Returns the internal mutex for this class.
Definition: ksocketbase.cpp:278
KNetwork::KBufferedSocket::waitForConnect
void waitForConnect()
Blocks until the connection is either established, or completely failed.
Definition: kbufferedsocket.cpp:310
KNetwork::KActiveSocketBase::setError
void setError(int status, SocketError error)
Sets the socket's error code and the I/O Device's status.
Definition: ksocketbase.cpp:309
KNetwork::KClientSocketBase::SocketState
SocketState
Socket states.
Definition: kclientsocketbase.h:71
KNetwork::KBufferedSocket::inputBuffer
KIOBufferBase * inputBuffer()
Retrieves the input buffer object.
Definition: kbufferedsocket.cpp:258
KNetwork::KBufferedSocket::readLine
QCString readLine()
Reads a line of data from the socket buffers.
Definition: kbufferedsocket.cpp:305
KNetwork::KBufferedSocket::slotWriteActivity
virtual void slotWriteActivity()
Slot called when there's write activity.
Definition: kbufferedsocket.cpp:367
KNetwork::KClientSocketBase::readBlock
virtual Q_LONG readBlock(char *data, Q_ULONG maxlen)
Reads data from a socket.
Definition: kclientsocketbase.cpp:301
KNetwork::KClientSocketBase::setState
void setState(SocketState state)
Sets the socket state to state.
Definition: kclientsocketbase.cpp:69
KNetwork::KClientSocketBase::readyRead
void readyRead()
This signal is emitted whenever the socket is ready for reading – i.e., there is data to be read in ...
KIOBufferBase
base for I/O buffer implementation
Definition: kiobuffer.h:45
KNetwork::KClientSocketBase::stateChanged
void stateChanged(int newstate)
This signal is emitted whenever the socket state changes.
KNetwork::KBufferedSocket::outputBuffer
KIOBufferBase * outputBuffer()
Retrieves the output buffer object.
Definition: kbufferedsocket.cpp:277
KNetwork::KBufferedSocket::setOutputBuffering
void setOutputBuffering(bool enable)
Sets the use of output buffering.
Definition: kbufferedsocket.cpp:263
KNetwork::KClientSocketBase::enableRead
virtual void enableRead(bool enable)
Enables the emission of the readyRead signal.
Definition: kclientsocketbase.cpp:388
KNetwork::KClientSocketBase::bytesAvailable
virtual Q_LONG bytesAvailable() const
Returns the number of bytes available on this socket.
Definition: kclientsocketbase.cpp:281
KNetwork::KSocketBase::setSocketDevice
virtual void setSocketDevice(KSocketDevice *device)
Sets the socket implementation to be used on this socket.
Definition: ksocketbase.cpp:136
KNetwork::KClientSocketBase::close
virtual void close()
Closes the socket.
Definition: kclientsocketbase.cpp:261
KNetwork::KBufferedSocket::readBlock
virtual Q_LONG readBlock(char *data, Q_ULONG maxlen)
Reads data from the socket.
Definition: kbufferedsocket.cpp:116
KNetwork::KClientSocketBase::stateChanging
virtual void stateChanging(SocketState newState)
This function is called by setState whenever the state changes.
Definition: kclientsocketbase.cpp:448
KNetwork::KBufferedSocket::setInputBuffering
void setInputBuffering(bool enable)
Sets the use of input buffering.
Definition: kbufferedsocket.cpp:244
KNetwork::KBufferedSocket::waitForMore
virtual Q_LONG waitForMore(int msecs, bool *timeout=0L)
Make use of buffers.
Definition: kbufferedsocket.cpp:104
KNetwork::KBufferedSocket::enableRead
virtual void enableRead(bool enable)
Catch changes.
Definition: kbufferedsocket.cpp:197
KNetwork::KClientSocketBase::emitsReadyRead
bool emitsReadyRead() const
Returns true if the readyRead signal is set to be emitted.
Definition: kclientsocketbase.cpp:383
KNetwork::KSocketBase::setBlocking
virtual bool setBlocking(bool enable)
Sets this socket's blocking mode.
Definition: ksocketbase.cpp:76
KNetwork::KSocketDevice
Low-level socket functionality.
Definition: ksocketdevice.h:50
KNetwork::KBufferedSocket::~KBufferedSocket
virtual ~KBufferedSocket()
Destructor.
Definition: kbufferedsocket.cpp:59
KNetwork::KBufferedSocket::enableWrite
virtual void enableWrite(bool enable)
Catch changes.
Definition: kbufferedsocket.cpp:214
KNetwork::KBufferedSocket::stateChanging
virtual void stateChanging(SocketState newState)
Catch connection to clear the buffers.
Definition: kbufferedsocket.cpp:226
KNetwork::KClientSocketBase::emitsReadyWrite
bool emitsReadyWrite() const
Returns true if the readyWrite signal is set to be emitted.
Definition: kclientsocketbase.cpp:398
KNetwork::KSocketBase::socketOptions
virtual int socketOptions() const
Retrieves the socket options that have been set.
Definition: ksocketbase.cpp:71
KNetwork::KClientSocketBase::enableWrite
virtual void enableWrite(bool enable)
Enables the emission of the readyWrite signal.
Definition: kclientsocketbase.cpp:403
KNetwork::KClientSocketBase::slotWriteActivity
virtual void slotWriteActivity()
This slot is connected to the write notifier's signal meaning the socket can write more data...
Definition: kclientsocketbase.cpp:419

KDE Home | KDE Accessibility Home | Description of Access Keys