kdatagramsocket.cpp
/* -*- C++ -*-
* Copyright (C) 2003,2004 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 <sys/types.h>
#include <sys/socket.h>
#include "ksocketaddress.h"
#include "kresolver.h"
#include "ksocketdevice.h"
#include "kdatagramsocket.h"
using namespace KNetwork;
/*
* TODO:
*
* don't use signals and slots to track state changes: use stateChanging
*
*/
KDatagramSocket::KDatagramSocket(QObject* parent, const char *name)
: KClientSocketBase(parent, name), d(0L)
{
peerResolver().setFamily(KResolver::KnownFamily);
localResolver().setFamily(KResolver::KnownFamily);
peerResolver().setSocketType(SOCK_DGRAM);
localResolver().setSocketType(SOCK_DGRAM);
localResolver().setFlags(KResolver::Passive);
// QObject::connect(localResolver(), SIGNAL(finished(KResolverResults)),
// this, SLOT(lookupFinishedLocal()));
QObject::connect(&peerResolver(), SIGNAL(finished(KResolverResults)),
this, SLOT(lookupFinishedPeer()));
QObject::connect(this, SIGNAL(hostFound()), this, SLOT(lookupFinishedLocal()));
}
KDatagramSocket::~KDatagramSocket()
{
// KClientSocketBase's destructor closes the socket
//delete d;
}
bool KDatagramSocket::bind(const QString& node, const QString& service)
{
if (state() >= Bound)
return false;
if (localResolver().isRunning())
localResolver().cancel(false);
// no, we must do a host lookup
localResolver().setAddress(node, service);
if (!lookup())
return false;
// see if lookup has finished already
// this also catches blocking mode, since lookup has to finish
// its processing if we're in blocking mode
if (state() > HostLookup)
return doBind();
return true;
}
bool KDatagramSocket::connect(const QString& node, const QString& service)
{
if (state() >= Connected)
return true; // already connected
if (peerResolver().nodeName() != node ||
peerResolver().serviceName() != service)
peerResolver().setAddress(node, service); // this resets the resolver's state
// KClientSocketBase::lookup only works if the state is Idle or HostLookup
// therefore, we store the old state, call the lookup routine and then set
// it back.
SocketState s = state();
setState(s == Connecting ? HostLookup : Idle);
bool ok = lookup();
if (!ok)
{
setState(s); // go back
return false;
}
// check if lookup is finished
// if we're in blocking mode, then the lookup has to be finished
if (state() == HostLookup)
{
// it hasn't finished
setState(Connecting);
emit stateChanged(Connecting);
return true;
}
// it has to be finished here
if (state() != Connected)
{
setState(Connecting);
emit stateChanged(Connecting);
lookupFinishedPeer();
}
return state() == Connected;
}
KDatagramPacket KDatagramSocket::receive()
{
Q_LONG size = bytesAvailable();
if (size == 0)
{
// nothing available yet to read
// wait for data if we're not blocking
if (blocking())
socketDevice()->waitForMore(-1); // wait forever
else
{
// mimic error
setError(IO_ReadError, WouldBlock);
emit gotError(WouldBlock);
return KDatagramPacket();
}
// try again
size = bytesAvailable();
}
QByteArray data(size);
KSocketAddress address;
// now do the reading
size = readBlock(data.data(), size, address);
if (size < 0)
// error has been set
return KDatagramPacket();
data.resize(size); // just to be sure
return KDatagramPacket(data, address);
}
Q_LONG KDatagramSocket::send(const KDatagramPacket& packet)
{
return writeBlock(packet.data(), packet.size(), packet.address());
}
Q_LONG KDatagramSocket::writeBlock(const char *data, Q_ULONG len, const KSocketAddress& to)
{
if (to.family() != AF_UNSPEC)
{
// make sure the socket is open at this point
if (!socketDevice()->isOpen())
// error handling will happen below
socketDevice()->create(to.family(), SOCK_DGRAM, 0);
}
return KClientSocketBase::writeBlock(data, len, to);
}
void KDatagramSocket::lookupFinishedLocal()
{
// bind lookup has finished and succeeded
// state() == HostFound
if (!doBind())
return; // failed binding
if (peerResults().count() > 0)
{
setState(Connecting);
emit stateChanged(Connecting);
lookupFinishedPeer();
}
}
void KDatagramSocket::lookupFinishedPeer()
{
// this function is called by lookupFinishedLocal above
// and is also connected to a signal
// so it might be called twice.
if (state() != Connecting)
return;
if (peerResults().count() == 0)
{
setState(Unconnected);
emit stateChanged(Unconnected);
return;
}
KResolverResults::ConstIterator it = peerResults().begin();
for ( ; it != peerResults().end(); ++it)
if (connect(*it))
{
// weee, we connected
setState(Connected); // this sets up signals
//setupSignals(); // setState sets up the signals
emit stateChanged(Connected);
emit connected(*it);
return;
}
// no connection
copyError();
setState(Unconnected);
emit stateChanged(Unconnected);
emit gotError(error());
}
bool KDatagramSocket::doBind()
{
if (localResults().count() == 0)
return true;
if (state() >= Bound)
return true; // already bound
KResolverResults::ConstIterator it = localResults().begin();
for ( ; it != localResults().end(); ++it)
if (bind(*it))
{
// bound
setupSignals();
return true;
}
// not bound
// no need to set state since it can only be HostFound already
copyError();
emit gotError(error());
return false;
}
void KDatagramSocket::setupSignals()
{
QSocketNotifier *n = socketDevice()->readNotifier();
if (n)
{
n->setEnabled(emitsReadyRead());
QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotReadActivity()));
}
else
return;
n = socketDevice()->writeNotifier();
if (n)
{
n->setEnabled(emitsReadyWrite());
QObject::connect(n, SIGNAL(activated(int)), this, SLOT(slotWriteActivity()));
}
else
return;
}
#include "kdatagramsocket.moc"
KNetwork::KSocketBase::blocking
bool blocking() const
Retrieves this socket's blocking mode.
Definition: ksocketbase.cpp:81
KNetwork::KDatagramSocket::connect
virtual bool connect(const QString &node=QString::null, const QString &service=QString::null)
"Connects" this socket to the given address.
Definition: kdatagramsocket.cpp:92
KNetwork::KSocketBase::socketDevice
KSocketDevice * socketDevice() const
Retrieves the socket implementation used on this socket.
Definition: ksocketbase.cpp:116
KNetwork::KClientSocketBase::state
SocketState state() const
Returns the current state for this socket.
Definition: kclientsocketbase.cpp:64
KNetwork::KDatagramSocket::receive
virtual KDatagramPacket receive()
Receives one datagram from the stream.
Definition: kdatagramsocket.cpp:134
KNetwork::KDatagramPacket::address
const KSocketAddress & address() const
Returns the socket address.
Definition: kdatagramsocket.h:137
KNetwork::KClientSocketBase::writeBlock
virtual Q_LONG writeBlock(const char *data, Q_ULONG len)
Writes data to the socket.
Definition: kclientsocketbase.cpp:349
KNetwork::KSocketDevice::writeNotifier
QSocketNotifier * writeNotifier() const
Returns a socket notifier for output on this socket.
Definition: ksocketdevice.cpp:627
KNetwork::KResolver::setFamily
void setFamily(int families)
Sets the allowed socket families.
Definition: kresolver.cpp:397
KNetwork::KClientSocketBase::lookup
virtual bool lookup()
Starts the lookup for peer and local hostnames as well as their services.
Definition: kclientsocketbase.cpp:131
KNetwork::KClientSocketBase::localResolver
KResolver & localResolver() const
Returns the internal KResolver object used for looking up the local host name and service...
Definition: kclientsocketbase.cpp:101
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::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::hostFound
void hostFound()
This signal is emitted when the lookup is successfully completed.
KNetwork::KResolverResults
Name and service resolution results.
Definition: kresolver.h:197
KNetwork::KSocketAddress::family
int family() const
Returns the family of this address.
Definition: ksocketaddress.cpp:489
KNetwork::KSocketDevice::readNotifier
QSocketNotifier * readNotifier() const
Returns a socket notifier for input on this socket.
Definition: ksocketdevice.cpp:609
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::KSocketDevice::create
virtual bool create(int family, int type, int protocol)
Creates a socket but don't connect or bind anywhere.
Definition: ksocketdevice.cpp:201
KNetwork::KActiveSocketBase::size
virtual Offset size() const
This call is not supported on sockets.
Definition: ksocketbase.h:507
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::peerResults
const KResolverResults & peerResults() const
Returns the internal list of resolved results for the peer address.
Definition: kclientsocketbase.cpp:96
KNetwork::KDatagramPacket::size
uint size() const
Returns the data length.
Definition: kdatagramsocket.h:119
KNetwork::KDatagramSocket::send
virtual Q_LONG send(const KDatagramPacket &packet)
Sends one datagram into the stream.
Definition: kdatagramsocket.cpp:168
KNetwork::KClientSocketBase::SocketState
SocketState
Socket states.
Definition: kclientsocketbase.h:71
KNetwork::KDatagramPacket::data
const QByteArray & data() const
Returns the data.
Definition: kdatagramsocket.h:107
KNetwork::KClientSocketBase::connected
void connected(const KResolverEntry &remote)
This socket is emitted when the socket successfully connects to a remote address. ...
KNetwork::KDatagramSocket::~KDatagramSocket
virtual ~KDatagramSocket()
Destructor.
Definition: kdatagramsocket.cpp:62
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::stateChanged
void stateChanged(int newstate)
This signal is emitted whenever the socket state changes.
KNetwork::KDatagramPacket
one datagram
Definition: kdatagramsocket.h:51
KNetwork::KClientSocketBase::bytesAvailable
virtual Q_LONG bytesAvailable() const
Returns the number of bytes available on this socket.
Definition: kclientsocketbase.cpp:281
KNetwork::KDatagramSocket::writeBlock
virtual Q_LONG writeBlock(const char *data, Q_ULONG len, const KSocketAddress &to)
Writes data to the socket.
Definition: kdatagramsocket.cpp:173
KNetwork::KClientSocketBase
Abstract client socket class.
Definition: kclientsocketbase.h:49
KNetwork::KResolver::setSocketType
void setSocketType(int type)
Sets the socket type we want.
Definition: kresolver.cpp:407
KNetwork::KClientSocketBase::emitsReadyRead
bool emitsReadyRead() const
Returns true if the readyRead signal is set to be emitted.
Definition: kclientsocketbase.cpp:383
KNetwork::KResolver::cancel
void cancel(bool emitSignal=true)
Cancels a running request.
Definition: kresolver.cpp:508
KNetwork::KClientSocketBase::localResults
const KResolverResults & localResults() const
Returns the internal list of resolved results for the local address.
Definition: kclientsocketbase.cpp:106
KNetwork::KClientSocketBase::emitsReadyWrite
bool emitsReadyWrite() const
Returns true if the readyWrite signal is set to be emitted.
Definition: kclientsocketbase.cpp:398
KNetwork::KSocketDevice::waitForMore
virtual Q_LONG waitForMore(int msecs, bool *timeout=0L)
Waits up to msecs for more data to be available on this socket.
Definition: ksocketdevice.cpp:379
KNetwork::KDatagramSocket::bind
virtual bool bind(const QString &node=QString::null, const QString &service=QString::null)
Performs host lookups.
Definition: kdatagramsocket.cpp:69
KNetwork::KResolver::setFlags
int setFlags(int flags)
Sets the flags.
Definition: kresolver.cpp:385
KNetwork::KClientSocketBase::peerResolver
KResolver & peerResolver() const
Returns the internal KResolver object used for looking up the peer host name and service.
Definition: kclientsocketbase.cpp:91
KNetwork::KDatagramSocket::KDatagramSocket
KDatagramSocket(QObject *parent=0L, const char *name=0L)
Default constructor.
Definition: kdatagramsocket.cpp:44
KNetwork::KResolver::setAddress
void setAddress(const QString &node, const QString &service)
Sets both the host and the service names.
Definition: kresolver.cpp:372
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