[atlantik-cvs] CVS: kdegames/atlantik/libatlantikclient klatencytimer.h,NONE,1.1 klatencytimer.cpp,NONE,1.1
[email protected] Thu, 24 Jul 2003 20:12:30 +0200 (CEST)
| Newsgroups | gmane.comp.kde.devel.atlantik |
|---|---|
| Message-ID | <[email protected]> |
Update of /home/kde/kdegames/atlantik/libatlantikclient In directory office:/tmp/cvs-serv32530 Added Files: klatencytimer.h klatencytimer.cpp Log Message: Initial revision of the KLatencyTimer class: simple UDP-based latency measurer --- NEW FILE: klatencytimer.h --- /* * Copyright (C) 2003 Thiago Macieira <[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef KLATENCYTIMER_H #define KLATENCYTIMER_H #include <qobject.h> #include <qstring.h> ///////////// // forward declarations // POSIX structs struct in_addr; struct in6_addr; // from standard Qt class QHostAddress; // from libqt-addon class QIpAddress; class QSocketAddress; // from KDE class KSocketAddress; class KLatencyTimerPrivate; /** * Simple measurement of latency, similar to ping. * * This class does a simple measurement of the latency to reach * the remote host. It is similar in behaviour to the system's * ping command, but it's not a ping and it also does not execute * any external programs. * * The method used consists of sending a dummy UDP packet to a * given or random port on the target host. When we receive the * reply telling us that the port is unreachable, we calculate * the time it took. * * @warning The method will time-out if we end up hitting an open * port or if it's blocked by firewall. Also note that * if we hit an open port, the other side may not like * the dummy packet we sent. * * @author Thiago Macieira * @version 0.9 * $Id: klatencytimer.h,v 1.1 2003/07/24 18:12:27 thiago Exp $ */ class KLatencyTimer: public QObject { Q_OBJECT public: /** * Default constructor. * * @param port the port to send the packet to * or -1 to choose one randomly */ explicit KLatencyTimer(int port = -1, QObject* parent = 0L, const char *name = 0L); /** * Destructor. */ virtual ~KLatencyTimer(); /** * Retrieves the stored port number */ int port() const { return m_port; } /** * Sets the port to the given value. Use value -1 to * make the class select a port number. * * @param port the port to send the packet to * or -1 to choose one randomly */ void setPort(int port); /** * Sets the target host. The @p host parameter must be * the string representation of a numeric IP address * (v4 or v6). Host names must be resolved by other * lookup means. * * @param node the target host */ void setHost(const QString& node); /** * @overload * * Sets the target host. * * @param node the target host */ void setHost(const in_addr& node); /** * @overload * * Sets the target host. * * @param node the target host */ void setHost(const in6_addr& node); /** * @overload * * Sets the target host. * * @param node the target host */ void setHost(const QHostAddress& node); /** * @overload * * Sets the target host. * * @param node the target host */ void setHost(const QIpAddress& node); /** * @overload * * Sets the target host from the host component * of the socket address. * * @param node the target host */ void setHost(const QSocketAddress& node); /** * @overload * * Sets the target host from the host component * of the socket address. * * @param node the target host */ void setHost(const KSocketAddress* node); /** * Starts the measurement. */ void start(); /** * Returns true if there has been a reply from the * target host. */ bool finished() const { return !m_running; } /** * Returns true if there was an error. */ bool error() const { return m_error; } /** * Returns the elapsed time since start. If the process * is not @ref finished, subsequent calls will return * different values. If it is finished, the value * won't change. * * @return the time in milliseconds */ int elapsed() const; public slots: /** * Cancels a running measurement. * * This function is provided as a slot so that you can make * constructs like following to create a time-out mechanism: * * \code * // time out after 2 seconds * QTimer::singleShot(2000, latencytimer, SLOT(cancel())); * \endcode */ void cancel(); signals: /** * Signals the receipt of an answer. * * @param msec the time in milliseconds that was given as result */ void answer(int msec); private slots: void activity(); private: int m_port; bool m_running; bool m_error; KLatencyTimerPrivate *d; }; #endif --- NEW FILE: klatencytimer.cpp --- /* * Copyright (C) 2003 Thiago Macieira <[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <qobject.h> #include <qstring.h> #include <qdatetime.h> #include <qhostaddress.h> #include <qsocketnotifier.h> #include <ksockaddr.h> #ifdef USE_QT_ADDON # include <qsocketaddress.h> #endif #include "klatencytimer.h" /* * temporary class exposing the needed functionality */ #ifdef USE_QT_ADDON class SocketAddress : public QInetSocketAddress { public: void setHost(const QString& host) { QInetSocketAddress::setHost(QIpAddress(host)); } void setHost(const in_addr& addr) { QInetSocketAddress::setHost(QIpAddress(&addr, 4)); } void setHost(const in6_addr& addr) { QInetSocketAddress::setHost(QIpAddress(&addr, 6)); } //using QInetAddress::setHost(const QIpAddress&); void setHost(const QIpAddress& addr) { QInetSocketAddress::setHost(addr); } unsigned size() const { return length(); } }; #else class SocketAddress : public KInetSocketAddress { }; #endif class KLatencyTimerPrivate { public: SocketAddress target; QTime time; QSocketNotifier* notifier; int sock; int elapsed; KLatencyTimerPrivate() : notifier(0L) { } }; KLatencyTimer::KLatencyTimer(int port, QObject* parent, const char* name) : QObject(parent, name), m_port(port), m_running(false), m_error(false), d(new KLatencyTimerPrivate) { } KLatencyTimer::~KLatencyTimer() { cancel(); delete d; } void KLatencyTimer::setPort(int port) { if (m_running) return; if (port < 0 || port > 0xffff) m_port = -1; else m_port = port; } void KLatencyTimer::setHost(const QString& node) { d->target.setHost(node); } void KLatencyTimer::setHost(const QHostAddress& node) { if (!node.isIp4Addr()) return; in_addr addr; addr.s_addr = node.ip4Addr(); d->target.setHost(addr); } #ifdef USE_QT_ADDON void KLatencyTimer::setHost(const QIpAddress& node) { d->target.setHost(node); } void KLatencyTimer::setHost(const QSocketAddress& node) { if (node.inet().ipVersion() != 0) d->target.setHost(node.inet().ipAddress()); } #endif void KLatencyTimer::setHost(const KSocketAddress* node) { const KInetSocketAddress *nodeinet = dynamic_cast<const KInetSocketAddress*>(node); if (nodeinet == 0L) return; if (nodeinet->size() == sizeof(sockaddr_in)) d->target.setHost(nodeinet->hostV4()); else d->target.setHost(nodeinet->hostV6()); } void KLatencyTimer::start() { if (m_running) return; // already running d->sock = ::socket(d->target.family(), SOCK_DGRAM, IPPROTO_UDP); if (d->sock == -1) { m_error = true; return; // error } // set non-blocking mode int fdflags = fcntl(d->sock, F_GETFL, 0); if (fdflags == -1) { m_error = true; return; // error } fdflags |= O_NONBLOCK; if (fcntl(d->sock, F_SETFL, fdflags) == -1) { m_error = true; return; // error } d->notifier = new QSocketNotifier(d->sock, QSocketNotifier::Read); d->notifier->setEnabled(true); connect(d->notifier, SIGNAL(activated(int)), this, SLOT(activity())); if (m_port != -1) d->target.setPort(m_port); else d->target.setPort(rand()); ::connect(d->sock, d->target.address(), d->target.size()); // now send a dummy packet to the destination static const char dummydata[] = "PING"; m_running = true; m_error = false; d->time.start(); ::write(d->sock, dummydata, sizeof dummydata - 1); } int KLatencyTimer::elapsed() const { if (m_running) return d->time.elapsed(); else return d->elapsed; } void KLatencyTimer::cancel() { if (!m_running) return; delete d->notifier; ::close(d->sock); m_running = false; m_error = false; } void KLatencyTimer::activity() { if (!m_running) return; // error! // retrieve the socket status int errcode; socklen_t len = sizeof(errcode); if (getsockopt(d->sock, SOL_SOCKET, SO_ERROR, (char*)&errcode, &len) == -1) { m_error = true; return; // error! } if (errcode != ECONNREFUSED) m_error = true; else m_error = false; d->elapsed = d->time.elapsed(); delete d->notifier; close(d->sock); m_running = false; emit answer(d->elapsed); } #include "klatencytimer.moc"