initial commit
This commit is contained in:
commit
9d20827c46
2469 changed files with 470994 additions and 0 deletions
1213
iris-legacy/iris/irisnet/Doxyfile
Normal file
1213
iris-legacy/iris/irisnet/Doxyfile
Normal file
File diff suppressed because it is too large
Load diff
4
iris-legacy/iris/irisnet/TODO
Normal file
4
iris-legacy/iris/irisnet/TODO
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
finish dns glue stuff
|
||||
win/mac/bsd/solaris netinterface
|
||||
if jdns ever does multiple interfaces, don't forget that late conflict should
|
||||
unpublish on all interfaces
|
||||
32
iris-legacy/iris/irisnet/irisnet.pri
Normal file
32
iris-legacy/iris/irisnet/irisnet.pri
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
QT *= network
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
# libidn
|
||||
#LIBS += -lidn
|
||||
|
||||
include(jdns/jdns.pri)
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/jdnsshared.h \
|
||||
$$PWD/irisnetexport.h \
|
||||
$$PWD/irisnetplugin.h \
|
||||
$$PWD/irisnetglobal.h \
|
||||
$$PWD/irisnetglobal_p.h \
|
||||
$$PWD/processquit.h \
|
||||
$$PWD/netinterface.h \
|
||||
$$PWD/netnames.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/jdnsshared.cpp \
|
||||
$$PWD/irisnetplugin.cpp \
|
||||
$$PWD/irisnetglobal.cpp \
|
||||
$$PWD/processquit.cpp \
|
||||
$$PWD/netinterface.cpp \
|
||||
$$PWD/netnames.cpp
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/netinterface_unix.cpp \
|
||||
$$PWD/netnames_jdns.cpp
|
||||
|
||||
include(legacy/legacy.pri)
|
||||
|
||||
7
iris-legacy/iris/irisnet/irisnet.pro
Normal file
7
iris-legacy/iris/irisnet/irisnet.pro
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
QT -= gui
|
||||
|
||||
include(irisnet.pri)
|
||||
|
||||
SOURCES += main.cpp
|
||||
36
iris-legacy/iris/irisnet/irisnetexport.h
Normal file
36
iris-legacy/iris/irisnet/irisnetexport.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef IRISNETEXPORT_H
|
||||
#define IRISNETEXPORT_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#ifdef IRISNET_STATIC
|
||||
# define IRISNET_EXPORT
|
||||
#else
|
||||
# ifdef IRISNET_MAKEDLL
|
||||
# define IRISNET_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define IRISNET_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
286
iris-legacy/iris/irisnet/irisnetglobal.cpp
Normal file
286
iris-legacy/iris/irisnet/irisnetglobal.cpp
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "irisnetglobal_p.h"
|
||||
|
||||
#include "irisnetplugin.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
// built-in providers
|
||||
extern IrisNetProvider *irisnet_createUnixNetProvider();
|
||||
extern IrisNetProvider *irisnet_createJDnsProvider();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// internal
|
||||
//----------------------------------------------------------------------------
|
||||
class PluginInstance
|
||||
{
|
||||
private:
|
||||
QPluginLoader *_loader;
|
||||
QObject *_instance;
|
||||
bool _ownInstance;
|
||||
|
||||
PluginInstance()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
static PluginInstance *fromFile(const QString &fname)
|
||||
{
|
||||
QPluginLoader *loader = new QPluginLoader(fname);
|
||||
if(!loader->load())
|
||||
{
|
||||
delete loader;
|
||||
return 0;
|
||||
}
|
||||
QObject *obj = loader->instance();
|
||||
if(!obj)
|
||||
{
|
||||
loader->unload();
|
||||
delete loader;
|
||||
return 0;
|
||||
}
|
||||
PluginInstance *i = new PluginInstance;
|
||||
i->_loader = loader;
|
||||
i->_instance = obj;
|
||||
i->_ownInstance = true;
|
||||
return i;
|
||||
}
|
||||
|
||||
static PluginInstance *fromStatic(QObject *obj)
|
||||
{
|
||||
PluginInstance *i = new PluginInstance;
|
||||
i->_loader = 0;
|
||||
i->_instance = obj;
|
||||
i->_ownInstance = false;
|
||||
return i;
|
||||
}
|
||||
|
||||
static PluginInstance *fromInstance(QObject *obj)
|
||||
{
|
||||
PluginInstance *i = new PluginInstance;
|
||||
i->_loader = 0;
|
||||
i->_instance = obj;
|
||||
i->_ownInstance = true;
|
||||
return i;
|
||||
}
|
||||
|
||||
~PluginInstance()
|
||||
{
|
||||
if(_ownInstance)
|
||||
delete _instance;
|
||||
|
||||
if(_loader)
|
||||
{
|
||||
_loader->unload();
|
||||
delete _loader;
|
||||
}
|
||||
}
|
||||
|
||||
void claim()
|
||||
{
|
||||
if(_loader)
|
||||
_loader->moveToThread(0);
|
||||
if(_ownInstance)
|
||||
_instance->moveToThread(0);
|
||||
}
|
||||
|
||||
QObject *instance()
|
||||
{
|
||||
return _instance;
|
||||
}
|
||||
|
||||
bool sameType(const PluginInstance *other)
|
||||
{
|
||||
if(!_instance || !other->_instance)
|
||||
return false;
|
||||
|
||||
if(qstrcmp(_instance->metaObject()->className(), other->_instance->metaObject()->className()) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class PluginManager
|
||||
{
|
||||
public:
|
||||
bool builtin_done;
|
||||
QStringList paths;
|
||||
QList<PluginInstance*> plugins;
|
||||
QList<IrisNetProvider*> providers;
|
||||
|
||||
PluginManager()
|
||||
{
|
||||
builtin_done = false;
|
||||
}
|
||||
|
||||
~PluginManager()
|
||||
{
|
||||
unload();
|
||||
}
|
||||
|
||||
bool tryAdd(PluginInstance *i, bool lowPriority = false)
|
||||
{
|
||||
// is it the right kind of plugin?
|
||||
IrisNetProvider *p = qobject_cast<IrisNetProvider*>(i->instance());
|
||||
if(!p)
|
||||
return false;
|
||||
|
||||
// make sure we don't have it already
|
||||
for(int n = 0; n < plugins.count(); ++n)
|
||||
{
|
||||
if(i->sameType(plugins[n]))
|
||||
return false;
|
||||
}
|
||||
|
||||
i->claim();
|
||||
plugins += i;
|
||||
if(lowPriority)
|
||||
providers.append(p);
|
||||
else
|
||||
providers.prepend(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
void addBuiltIn(IrisNetProvider *p)
|
||||
{
|
||||
PluginInstance *i = PluginInstance::fromInstance(p);
|
||||
if(!tryAdd(i, true))
|
||||
delete i;
|
||||
}
|
||||
|
||||
void scan()
|
||||
{
|
||||
if(!builtin_done)
|
||||
{
|
||||
addBuiltIn(irisnet_createUnixNetProvider());
|
||||
addBuiltIn(irisnet_createJDnsProvider());
|
||||
builtin_done = true;
|
||||
}
|
||||
|
||||
QObjectList list = QPluginLoader::staticInstances();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
PluginInstance *i = PluginInstance::fromStatic(list[n]);
|
||||
if(!tryAdd(i))
|
||||
delete i;
|
||||
}
|
||||
for(int n = 0; n < paths.count(); ++n)
|
||||
{
|
||||
QDir dir(paths[n]);
|
||||
if(!dir.exists())
|
||||
continue;
|
||||
|
||||
QStringList entries = dir.entryList();
|
||||
for(int k = 0; k < entries.count(); ++k)
|
||||
{
|
||||
QFileInfo fi(dir.filePath(entries[k]));
|
||||
if(!fi.exists())
|
||||
continue;
|
||||
QString fname = fi.filePath();
|
||||
PluginInstance *i = PluginInstance::fromFile(fname);
|
||||
if(!i)
|
||||
continue;
|
||||
|
||||
if(!tryAdd(i))
|
||||
delete i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unload()
|
||||
{
|
||||
qDeleteAll(plugins);
|
||||
plugins.clear();
|
||||
providers.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class IrisNetGlobal
|
||||
{
|
||||
public:
|
||||
QMutex m;
|
||||
PluginManager pluginManager;
|
||||
QList<IrisNetCleanUpFunction> cleanupList;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QMutex, global_mutex)
|
||||
static IrisNetGlobal *global = 0;
|
||||
|
||||
static void deinit();
|
||||
|
||||
static void init()
|
||||
{
|
||||
QMutexLocker locker(global_mutex());
|
||||
if(global)
|
||||
return;
|
||||
|
||||
global = new IrisNetGlobal;
|
||||
qAddPostRoutine(deinit);
|
||||
}
|
||||
|
||||
void deinit()
|
||||
{
|
||||
if(!global)
|
||||
return;
|
||||
|
||||
while(!global->cleanupList.isEmpty())
|
||||
(global->cleanupList.takeFirst())();
|
||||
|
||||
delete global;
|
||||
global = 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Global
|
||||
//----------------------------------------------------------------------------
|
||||
void irisNetSetPluginPaths(const QStringList &paths)
|
||||
{
|
||||
init();
|
||||
|
||||
QMutexLocker locker(&global->m);
|
||||
global->pluginManager.paths = paths;
|
||||
}
|
||||
|
||||
void irisNetCleanup()
|
||||
{
|
||||
deinit();
|
||||
}
|
||||
|
||||
void irisNetAddPostRoutine(IrisNetCleanUpFunction func)
|
||||
{
|
||||
init();
|
||||
|
||||
QMutexLocker locker(&global->m);
|
||||
global->cleanupList.prepend(func);
|
||||
}
|
||||
|
||||
QList<IrisNetProvider*> irisNetProviders()
|
||||
{
|
||||
init();
|
||||
|
||||
QMutexLocker locker(&global->m);
|
||||
global->pluginManager.scan();
|
||||
return global->pluginManager.providers;
|
||||
}
|
||||
|
||||
}
|
||||
39
iris-legacy/iris/irisnet/irisnetglobal.h
Normal file
39
iris-legacy/iris/irisnet/irisnetglobal.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef IRISNETGLOBAL_H
|
||||
#define IRISNETGLOBAL_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include "irisnetexport.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
// set the directories for plugins. call before doing anything else.
|
||||
IRISNET_EXPORT void irisNetSetPluginPaths(const QStringList &paths);
|
||||
|
||||
// free any shared data and plugins.
|
||||
// note: this is automatically called when qapp shuts down.
|
||||
IRISNET_EXPORT void irisNetCleanup();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
36
iris-legacy/iris/irisnet/irisnetglobal_p.h
Normal file
36
iris-legacy/iris/irisnet/irisnetglobal_p.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef IRISNETGLOBAL_P_H
|
||||
#define IRISNETGLOBAL_P_H
|
||||
|
||||
#include "irisnetglobal.h"
|
||||
#include "irisnetplugin.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
typedef void (*IrisNetCleanUpFunction)();
|
||||
|
||||
IRISNET_EXPORT void irisNetAddPostRoutine(IrisNetCleanUpFunction func);
|
||||
IRISNET_EXPORT QList<IrisNetProvider*> irisNetProviders();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
52
iris-legacy/iris/irisnet/irisnetplugin.cpp
Normal file
52
iris-legacy/iris/irisnet/irisnetplugin.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "irisnetplugin.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// IrisNetProvider
|
||||
//----------------------------------------------------------------------------
|
||||
IrisNetProvider::~IrisNetProvider()
|
||||
{
|
||||
}
|
||||
|
||||
NetInterfaceProvider *IrisNetProvider::createNetInterfaceProvider()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
NameProvider *IrisNetProvider::createNameProviderInternet()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
NameProvider *IrisNetProvider::createNameProviderLocal()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ServiceProvider *IrisNetProvider::createServiceProvider()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
127
iris-legacy/iris/irisnet/irisnetplugin.h
Normal file
127
iris-legacy/iris/irisnet/irisnetplugin.h
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef IRISNETPLUGIN_H
|
||||
#define IRISNETPLUGIN_H
|
||||
|
||||
#include "irisnetglobal.h"
|
||||
#include "netinterface.h"
|
||||
#include "netnames.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
class NetInterfaceProvider;
|
||||
class NameProvider;
|
||||
class ServiceProvider;
|
||||
|
||||
class IRISNET_EXPORT IrisNetProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
virtual ~IrisNetProvider();
|
||||
|
||||
virtual NetInterfaceProvider *createNetInterfaceProvider();
|
||||
virtual NameProvider *createNameProviderInternet();
|
||||
virtual NameProvider *createNameProviderLocal();
|
||||
virtual ServiceProvider *createServiceProvider();
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT NetInterfaceProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class Info
|
||||
{
|
||||
public:
|
||||
QString id, name;
|
||||
bool isLoopback;
|
||||
QList<QHostAddress> addresses;
|
||||
QHostAddress gateway;
|
||||
};
|
||||
|
||||
NetInterfaceProvider(QObject *parent = 0) : QObject(parent) {}
|
||||
|
||||
// calling start should populate an initial list that can be
|
||||
// immediately fetched. do not signal updated() for this.
|
||||
virtual void start() = 0;
|
||||
virtual QList<Info> interfaces() const = 0;
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT NameProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NameProvider(QObject *parent = 0) : QObject(parent) {}
|
||||
|
||||
virtual int resolve_start(const QByteArray &name, int qType, bool longLived) = 0;
|
||||
virtual void resolve_stop(int id) = 0;
|
||||
|
||||
// transfer from local back to internet
|
||||
virtual void resolve_localResultsReady(int id, const QList<XMPP::NameRecord> &results) = 0;
|
||||
virtual void resolve_localError(int id, XMPP::NameResolver::Error e) = 0;
|
||||
|
||||
signals:
|
||||
void resolve_resultsReady(int id, const QList<XMPP::NameRecord> &results);
|
||||
void resolve_error(int id, XMPP::NameResolver::Error e);
|
||||
|
||||
// transfer from internet to local provider
|
||||
void resolve_useLocal(int id, const QByteArray &name);
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT ServiceProvider : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServiceProvider(QObject *parent = 0) : QObject(parent) {}
|
||||
|
||||
virtual int browse_start(const QString &type, const QString &domain) = 0;
|
||||
virtual void browse_stop(int id) = 0;
|
||||
virtual int resolve_start(const QByteArray &name) = 0;
|
||||
virtual void resolve_stop(int id) = 0;
|
||||
virtual int publish_start(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes) = 0;
|
||||
virtual int publish_update(const QMap<QString,QByteArray> &attributes) = 0;
|
||||
virtual void publish_cancel(int id) = 0;
|
||||
virtual int publish_extra_start(int pub_id, const NameRecord &name) = 0;
|
||||
virtual int publish_extra_update(int id, const NameRecord &name) = 0;
|
||||
virtual void publish_extra_cancel(int id) = 0;
|
||||
|
||||
signals:
|
||||
void browse_instanceAvailable(int id, const XMPP::ServiceInstance &instance);
|
||||
void browse_instanceUnavailable(int id, const XMPP::ServiceInstance &instance);
|
||||
void browse_error(int id);
|
||||
void resolve_resultsReady(int id, const QHostAddress &address, int port);
|
||||
void resolve_error(int id);
|
||||
void publish_published(int id);
|
||||
void publish_error(int id, XMPP::ServiceLocalPublisher::Error e);
|
||||
void publish_extra_published(int id);
|
||||
void publish_extra_error(int id, XMPP::ServiceLocalPublisher::Error e);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_INTERFACE(XMPP::IrisNetProvider, "com.affinix.irisnet.IrisNetProvider/1.0")
|
||||
Q_DECLARE_INTERFACE(XMPP::NetInterfaceProvider, "com.affinix.irisnet.NetInterfaceProvider/1.0")
|
||||
Q_DECLARE_INTERFACE(XMPP::NameProvider, "com.affinix.irisnet.NameProvider/1.0")
|
||||
Q_DECLARE_INTERFACE(XMPP::ServiceProvider, "com.affinix.irisnet.ServiceProvider/1.0")
|
||||
|
||||
#endif
|
||||
85
iris-legacy/iris/irisnet/jdns/README
Normal file
85
iris-legacy/iris/irisnet/jdns/README
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
JDNS
|
||||
----
|
||||
Date: October 1st, 2005
|
||||
Author: Justin Karneges <justin@affinix.com>
|
||||
|
||||
JDNS is a simple DNS implementation that can perform normal DNS queries
|
||||
of any record type (notably SRV), as well as Multicast DNS queries and
|
||||
advertising. Multicast support is based on Jeremie Miller's "mdnsd"
|
||||
implementation.
|
||||
|
||||
For maximum flexibility, JDNS is written in C with no direct dependencies,
|
||||
and is licensed under the MIT license. Your application must supply
|
||||
functionality to JDNS, such as UDP sending/receiving, via callbacks.
|
||||
|
||||
For Qt users there is a wrapper available called QJDns. jdns.pri can
|
||||
be used to include everything into a qmake project. jdns.pro will build
|
||||
the sample Qt-based commandline tool 'jdns'.
|
||||
|
||||
Features:
|
||||
- DNS client "stub" resolver
|
||||
- Can fetch any record type, but provides handy decoding for many
|
||||
known types: A, AAAA, SRV, MX, TXT, etc.
|
||||
- Performs retries, caching/expiration, and CNAME following
|
||||
- Algorithm logic adapted from Q3Dns
|
||||
- Multicast queries
|
||||
- Multicast advertising
|
||||
|
||||
Why?
|
||||
- Trolltech is phasing out the Qt DNS implementation, which in Qt 4 has
|
||||
been relegated to the Qt3Support module. A replacement was desired.
|
||||
|
||||
- While there are many DNS libraries available, at the time of this
|
||||
writing it was (and still may be) hard to find one that satisfies
|
||||
three essential conditions: cross-platform friendliness (and this
|
||||
includes Windows 9x!), the ability to integrate into existing
|
||||
eventloops, sensible licensing (ie, not GPL).
|
||||
|
||||
How to use:
|
||||
- Prepare callbacks and call jdns_session_new()
|
||||
- Call jdns_init_unicast() or jdns_init_multicast(), depending on
|
||||
if you want regular or multicast DNS. If you want both kinds, you
|
||||
can always make two sessions.
|
||||
- Make queries and have fun
|
||||
- Call jdns_step() at the right times to advance JDNS processing
|
||||
|
||||
What is left to you:
|
||||
- The callback functions, obviously.
|
||||
- Querying for several "qualified" names. Here is what Q3Dns does:
|
||||
Query for name as provided
|
||||
Query for name + '.domain' (for every domain the computer is in)
|
||||
- Detecting for '.local' in a name to be queried, and using that
|
||||
to decide whether to query via Multicast or normal DNS.
|
||||
- Recognition of IP addresses. If you want an IP address to resolve
|
||||
to itself, then do that yourself. Passing an IP address as a DNS
|
||||
name to JDNS won't work (especially since it wouldn't make any
|
||||
sense in some contexts, like SRV).
|
||||
- Recognition of known hosts. If you want this, compare inputs against
|
||||
jdns_system_dnsparams().
|
||||
- For zeroconf/Bonjour, keep in mind that JDNS only provides Multicast
|
||||
DNS capability. DNS-SD and any higher layers would be your job.
|
||||
|
||||
Using a custom DNS implementation has the drawback that it is difficult
|
||||
to take advantage of platform-specific features (for example, an OS-wide
|
||||
DNS cache or LDAP integration).
|
||||
|
||||
An application strategy for normal DNS should probably be:
|
||||
- If an A or AAAA record is desired, use a native lookup.
|
||||
- Else, if the platform has advanced DNS features already (ie,
|
||||
res_query), use those.
|
||||
- Else, use JDNS.
|
||||
|
||||
However, it may not be a bad idea at first to use JDNS for all occasions,
|
||||
so that it can be debugged.
|
||||
|
||||
For Multicast DNS, awareness of the platform is doubly important. There
|
||||
should only be one Multicast DNS "Responder" per computer, and using JDNS
|
||||
at the same time could result in a conflict.
|
||||
|
||||
An application strategy for Multicast DNS should be:
|
||||
- If the platform has a Multicast DNS daemon installed already, use
|
||||
it somehow.
|
||||
- Else, use JDNS.
|
||||
|
||||
Have fun!
|
||||
|
||||
1
iris-legacy/iris/irisnet/jdns/TODO
Normal file
1
iris-legacy/iris/irisnet/jdns/TODO
Normal file
|
|
@ -0,0 +1 @@
|
|||
(nothing)
|
||||
3176
iris-legacy/iris/irisnet/jdns/jdns.c
Normal file
3176
iris-legacy/iris/irisnet/jdns/jdns.c
Normal file
File diff suppressed because it is too large
Load diff
490
iris-legacy/iris/irisnet/jdns/jdns.h
Normal file
490
iris-legacy/iris/irisnet/jdns/jdns.h
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_H
|
||||
#define JDNS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*jdns_object_dtor_func)(void *);
|
||||
typedef void *(*jdns_object_cctor_func)(const void *);
|
||||
|
||||
#define JDNS_OBJECT \
|
||||
jdns_object_dtor_func dtor; \
|
||||
jdns_object_cctor_func cctor;
|
||||
|
||||
#define JDNS_OBJECT_NEW(name) \
|
||||
(name##_t *)jdns_object_new(sizeof(name##_t), \
|
||||
(jdns_object_dtor_func)name##_delete, \
|
||||
(jdns_object_cctor_func)name##_copy);
|
||||
|
||||
typedef struct jdns_object
|
||||
{
|
||||
JDNS_OBJECT
|
||||
} jdns_object_t;
|
||||
|
||||
void *jdns_object_new(int size, void (*dtor)(void *),
|
||||
void *(*cctor)(const void *));
|
||||
void *jdns_object_copy(const void *a);
|
||||
void jdns_object_delete(void *a);
|
||||
void jdns_object_free(void *a);
|
||||
|
||||
#define JDNS_LIST_DECLARE(name) \
|
||||
JDNS_OBJECT \
|
||||
int count; \
|
||||
name##_t **item;
|
||||
|
||||
typedef struct jdns_list
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int count;
|
||||
void **item;
|
||||
int valueList;
|
||||
int autoDelete;
|
||||
} jdns_list_t;
|
||||
|
||||
jdns_list_t *jdns_list_new();
|
||||
jdns_list_t *jdns_list_copy(const jdns_list_t *a);
|
||||
void jdns_list_delete(jdns_list_t *a);
|
||||
void jdns_list_clear(jdns_list_t *a);
|
||||
void jdns_list_insert(jdns_list_t *a, void *item, int pos);
|
||||
void jdns_list_insert_value(jdns_list_t *a, const void *item, int pos);
|
||||
void jdns_list_remove(jdns_list_t *a, void *item);
|
||||
void jdns_list_remove_at(jdns_list_t *a, int pos);
|
||||
|
||||
typedef struct jdns_string
|
||||
{
|
||||
JDNS_OBJECT
|
||||
unsigned char *data;
|
||||
int size;
|
||||
} jdns_string_t;
|
||||
|
||||
jdns_string_t *jdns_string_new();
|
||||
jdns_string_t *jdns_string_copy(const jdns_string_t *s);
|
||||
void jdns_string_delete(jdns_string_t *s);
|
||||
void jdns_string_set(jdns_string_t *s, const unsigned char *str,
|
||||
int str_len);
|
||||
void jdns_string_set_cstr(jdns_string_t *s, const char *str);
|
||||
|
||||
// overlays jdns_list
|
||||
typedef struct jdns_stringlist
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int count;
|
||||
jdns_string_t **item;
|
||||
} jdns_stringlist_t;
|
||||
|
||||
jdns_stringlist_t *jdns_stringlist_new();
|
||||
jdns_stringlist_t *jdns_stringlist_copy(const jdns_stringlist_t *a);
|
||||
void jdns_stringlist_delete(jdns_stringlist_t *a);
|
||||
void jdns_stringlist_append(jdns_stringlist_t *a, const jdns_string_t *str);
|
||||
|
||||
typedef struct jdns_address
|
||||
{
|
||||
int isIpv6;
|
||||
union
|
||||
{
|
||||
unsigned long int v4;
|
||||
unsigned char *v6; // 16 bytes
|
||||
} addr;
|
||||
char *c_str;
|
||||
} jdns_address_t;
|
||||
|
||||
jdns_address_t *jdns_address_new();
|
||||
jdns_address_t *jdns_address_copy(const jdns_address_t *a);
|
||||
void jdns_address_delete(jdns_address_t *a);
|
||||
void jdns_address_set_ipv4(jdns_address_t *a, unsigned long int ipv4);
|
||||
void jdns_address_set_ipv6(jdns_address_t *a, const unsigned char *ipv6);
|
||||
// return 1 if string was ok, else 0. Note: IPv4 addresses only!
|
||||
int jdns_address_set_cstr(jdns_address_t *a, const char *str);
|
||||
// return 1 if the same, else 0
|
||||
int jdns_address_cmp(const jdns_address_t *a, const jdns_address_t *b);
|
||||
|
||||
// convenient predefined addresses/ports
|
||||
#define JDNS_UNICAST_PORT 53
|
||||
#define JDNS_MULTICAST_PORT 5353
|
||||
jdns_address_t *jdns_address_multicast4_new(); // 224.0.0.251
|
||||
jdns_address_t *jdns_address_multicast6_new(); // FF02::FB
|
||||
|
||||
typedef struct jdns_server
|
||||
{
|
||||
unsigned char *name;
|
||||
int port; // SRV only
|
||||
int priority;
|
||||
int weight; // SRV only
|
||||
} jdns_server_t;
|
||||
|
||||
jdns_server_t *jdns_server_new();
|
||||
jdns_server_t *jdns_server_copy(const jdns_server_t *s);
|
||||
void jdns_server_delete(jdns_server_t *s);
|
||||
void jdns_server_set_name(jdns_server_t *s, const unsigned char *name);
|
||||
|
||||
typedef struct jdns_nameserver
|
||||
{
|
||||
jdns_address_t *address;
|
||||
int port;
|
||||
} jdns_nameserver_t;
|
||||
|
||||
jdns_nameserver_t *jdns_nameserver_new();
|
||||
jdns_nameserver_t *jdns_nameserver_copy(const jdns_nameserver_t *a);
|
||||
void jdns_nameserver_delete(jdns_nameserver_t *a);
|
||||
void jdns_nameserver_set(jdns_nameserver_t *a, const jdns_address_t *addr,
|
||||
int port);
|
||||
|
||||
typedef struct jdns_nameserverlist
|
||||
{
|
||||
int count;
|
||||
jdns_nameserver_t **item;
|
||||
} jdns_nameserverlist_t;
|
||||
|
||||
jdns_nameserverlist_t *jdns_nameserverlist_new();
|
||||
jdns_nameserverlist_t *jdns_nameserverlist_copy(
|
||||
const jdns_nameserverlist_t *a);
|
||||
void jdns_nameserverlist_delete(jdns_nameserverlist_t *a);
|
||||
void jdns_nameserverlist_append(jdns_nameserverlist_t *a,
|
||||
const jdns_address_t *addr, int port);
|
||||
|
||||
typedef struct jdns_dnshost
|
||||
{
|
||||
jdns_string_t *name;
|
||||
jdns_address_t *address;
|
||||
} jdns_dnshost_t;
|
||||
|
||||
typedef struct jdns_dnshostlist
|
||||
{
|
||||
int count;
|
||||
jdns_dnshost_t **item;
|
||||
} jdns_dnshostlist_t;
|
||||
|
||||
typedef struct jdns_dnsparams
|
||||
{
|
||||
jdns_nameserverlist_t *nameservers;
|
||||
jdns_stringlist_t *domains;
|
||||
jdns_dnshostlist_t *hosts;
|
||||
} jdns_dnsparams_t;
|
||||
|
||||
jdns_dnsparams_t *jdns_dnsparams_new();
|
||||
jdns_dnsparams_t *jdns_dnsparams_copy(jdns_dnsparams_t *a);
|
||||
void jdns_dnsparams_delete(jdns_dnsparams_t *a);
|
||||
void jdns_dnsparams_append_nameserver(jdns_dnsparams_t *a,
|
||||
const jdns_address_t *addr, int port);
|
||||
void jdns_dnsparams_append_domain(jdns_dnsparams_t *a,
|
||||
const jdns_string_t *domain);
|
||||
void jdns_dnsparams_append_host(jdns_dnsparams_t *a,
|
||||
const jdns_string_t *name, const jdns_address_t *address);
|
||||
|
||||
#define JDNS_RTYPE_A 1
|
||||
#define JDNS_RTYPE_AAAA 28
|
||||
#define JDNS_RTYPE_MX 15
|
||||
#define JDNS_RTYPE_SRV 33
|
||||
#define JDNS_RTYPE_CNAME 5
|
||||
#define JDNS_RTYPE_PTR 12
|
||||
#define JDNS_RTYPE_TXT 16
|
||||
#define JDNS_RTYPE_HINFO 13
|
||||
#define JDNS_RTYPE_NS 2
|
||||
#define JDNS_RTYPE_ANY 255
|
||||
|
||||
typedef struct jdns_rr
|
||||
{
|
||||
unsigned char *owner;
|
||||
int ttl;
|
||||
int type;
|
||||
int qclass;
|
||||
int rdlength;
|
||||
unsigned char *rdata;
|
||||
int haveKnown;
|
||||
|
||||
union
|
||||
{
|
||||
jdns_address_t *address; // for A, AAAA
|
||||
jdns_server_t *server; // for MX, SRV
|
||||
unsigned char *name; // for CNAME, PTR, NS
|
||||
jdns_stringlist_t *texts; // for TXT
|
||||
struct
|
||||
{
|
||||
jdns_string_t *cpu;
|
||||
jdns_string_t *os;
|
||||
} hinfo; // for HINFO
|
||||
} data;
|
||||
} jdns_rr_t;
|
||||
|
||||
jdns_rr_t *jdns_rr_new();
|
||||
jdns_rr_t *jdns_rr_copy(const jdns_rr_t *r);
|
||||
void jdns_rr_delete(jdns_rr_t *r);
|
||||
void jdns_rr_set_owner(jdns_rr_t *r, const unsigned char *name);
|
||||
void jdns_rr_set_record(jdns_rr_t *r, int type, const unsigned char *rdata,
|
||||
int rdlength);
|
||||
void jdns_rr_set_A(jdns_rr_t *r, const jdns_address_t *address);
|
||||
void jdns_rr_set_AAAA(jdns_rr_t *r, const jdns_address_t *address);
|
||||
void jdns_rr_set_MX(jdns_rr_t *r, const unsigned char *name, int priority);
|
||||
void jdns_rr_set_SRV(jdns_rr_t *r, const unsigned char *name, int port,
|
||||
int priority, int weight);
|
||||
void jdns_rr_set_CNAME(jdns_rr_t *r, const unsigned char *name);
|
||||
void jdns_rr_set_PTR(jdns_rr_t *r, const unsigned char *name);
|
||||
void jdns_rr_set_TXT(jdns_rr_t *r, const jdns_stringlist_t *texts);
|
||||
void jdns_rr_set_HINFO(jdns_rr_t *r, const jdns_string_t *cpu,
|
||||
const jdns_string_t *os);
|
||||
void jdns_rr_set_NS(jdns_rr_t *r, const unsigned char *name);
|
||||
// note: only works on known types
|
||||
int jdns_rr_verify(const jdns_rr_t *r);
|
||||
|
||||
typedef struct jdns_response
|
||||
{
|
||||
int answerCount;
|
||||
jdns_rr_t **answerRecords;
|
||||
int authorityCount;
|
||||
jdns_rr_t **authorityRecords;
|
||||
int additionalCount;
|
||||
jdns_rr_t **additionalRecords;
|
||||
} jdns_response_t;
|
||||
|
||||
jdns_response_t *jdns_response_new();
|
||||
jdns_response_t *jdns_response_copy(const jdns_response_t *r);
|
||||
void jdns_response_delete(jdns_response_t *r);
|
||||
void jdns_response_append_answer(jdns_response_t *r, const jdns_rr_t *rr);
|
||||
void jdns_response_append_authority(jdns_response_t *r, const jdns_rr_t *rr);
|
||||
void jdns_response_append_additional(jdns_response_t *r,
|
||||
const jdns_rr_t *rr);
|
||||
|
||||
#define JDNS_PUBLISH_SHARED 0x0001
|
||||
#define JDNS_PUBLISH_UNIQUE 0x0002
|
||||
|
||||
#define JDNS_STEP_TIMER 0x0001
|
||||
#define JDNS_STEP_HANDLE 0x0002
|
||||
|
||||
#define JDNS_EVENT_RESPONSE 0x0001
|
||||
#define JDNS_EVENT_PUBLISH 0x0002
|
||||
#define JDNS_EVENT_SHUTDOWN 0x0003
|
||||
|
||||
#define JDNS_STATUS_SUCCESS 0x0001
|
||||
#define JDNS_STATUS_NXDOMAIN 0x0002
|
||||
#define JDNS_STATUS_ERROR 0x0003
|
||||
#define JDNS_STATUS_TIMEOUT 0x0004
|
||||
#define JDNS_STATUS_CONFLICT 0x0005
|
||||
|
||||
typedef struct jdns_session jdns_session_t;
|
||||
|
||||
typedef struct jdns_callbacks
|
||||
{
|
||||
void *app; // user-supplied context
|
||||
|
||||
// time_now:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// return: milliseconds since session started
|
||||
int (*time_now)(jdns_session_t *s, void *app);
|
||||
|
||||
// rand_int:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// return: random integer between 0-65535
|
||||
int (*rand_int)(jdns_session_t *s, void *app);
|
||||
|
||||
// debug_line:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// str: a line of debug text
|
||||
// return: nothing
|
||||
void (*debug_line)(jdns_session_t *s, void *app, const char *str);
|
||||
|
||||
// udp_bind:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// addr: ip address of interface to bind to. 0 for all
|
||||
// port: port of interface to bind to. 0 for any
|
||||
// maddr: multicast address. 0 if not using multicast
|
||||
// return: handle (>0) of bound socket, or 0 on error
|
||||
// note: for multicast, the following must be done:
|
||||
// use SO_REUSEPORT to share with other mdns programs
|
||||
// use IP_ADD_MEMBERSHIP to associate addr and maddr
|
||||
// set IP_MULTICAST_TTL to 255
|
||||
int (*udp_bind)(jdns_session_t *s, void *app,
|
||||
const jdns_address_t *addr, int port,
|
||||
const jdns_address_t *maddr);
|
||||
|
||||
// udp_unbind:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// handle: handle of socket obtained with udp_bind
|
||||
// return: nothing
|
||||
void (*udp_unbind)(jdns_session_t *s, void *app, int handle);
|
||||
|
||||
// udp_read:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// handle: handle of socket obtained with udp_bind
|
||||
// addr: store ip address of sender
|
||||
// port: store port of sender
|
||||
// buf: store packet content
|
||||
// bufsize: value contains max size, to be changed to real size
|
||||
// return: 1 if packet read, 0 if none available
|
||||
int (*udp_read)(jdns_session_t *s, void *app, int handle,
|
||||
jdns_address_t *addr, int *port, unsigned char *buf,
|
||||
int *bufsize);
|
||||
|
||||
// udp_write:
|
||||
// s: session
|
||||
// app: user-supplied context
|
||||
// handle: handle of socket obtained with udp_bind
|
||||
// addr: ip address of recipient
|
||||
// port: port of recipient
|
||||
// buf: packet content
|
||||
// bufsize: size of packet
|
||||
// return: 1 if packet taken for writing, 0 if this is a bad time
|
||||
int (*udp_write)(jdns_session_t *s, void *app, int handle,
|
||||
const jdns_address_t *addr, int port, unsigned char *buf,
|
||||
int bufsize);
|
||||
} jdns_callbacks_t;
|
||||
|
||||
typedef struct jdns_event
|
||||
{
|
||||
int type; // JDNS_EVENT
|
||||
int id; // query id or publish id
|
||||
|
||||
// for query, this can be SUCCESS, NXDOMAIN, ERROR, or TIMEOUT
|
||||
// for publish, this can be SUCCESS, ERROR, or CONFLICT
|
||||
int status;
|
||||
|
||||
// for query
|
||||
jdns_response_t *response;
|
||||
} jdns_event_t;
|
||||
|
||||
void jdns_event_delete(jdns_event_t *e);
|
||||
|
||||
// jdns_session_new:
|
||||
// callbacks: the struct of callbacks
|
||||
// return: newly allocated session
|
||||
jdns_session_t *jdns_session_new(jdns_callbacks_t *callbacks);
|
||||
|
||||
// jdns_session_delete:
|
||||
// s: session to free
|
||||
// return: nothing
|
||||
void jdns_session_delete(jdns_session_t *s);
|
||||
|
||||
// jdns_init_unicast:
|
||||
// s: session
|
||||
// addr: ip address of interface to bind to. NULL for all
|
||||
// port: port of interface to bind to. 0 for any
|
||||
// return: 1 on success, 0 on failure
|
||||
int jdns_init_unicast(jdns_session_t *s, const jdns_address_t *addr,
|
||||
int port);
|
||||
|
||||
// jdns_init_multicast:
|
||||
// s: session
|
||||
// addr: ip address of interface to bind to. NULL for all
|
||||
// port: port of interface to bind to. 0 for any
|
||||
// addr: multicast address to associate with. cannot be NULL
|
||||
// return: 1 on success, 0 on failure
|
||||
int jdns_init_multicast(jdns_session_t *s, const jdns_address_t *addr,
|
||||
int port, const jdns_address_t *maddr);
|
||||
|
||||
// jdns_shutdown:
|
||||
// s: session
|
||||
// return: nothing
|
||||
void jdns_shutdown(jdns_session_t *s);
|
||||
|
||||
// jdns_set_nameservers:
|
||||
// s: session
|
||||
// nslist: list of nameservers
|
||||
// return nothing
|
||||
void jdns_set_nameservers(jdns_session_t *s,
|
||||
const jdns_nameserverlist_t *nslist);
|
||||
|
||||
// jdns_probe:
|
||||
// s: session
|
||||
// return: nothing
|
||||
void jdns_probe(jdns_session_t *s);
|
||||
|
||||
// jdns_query:
|
||||
// s: session
|
||||
// name: the name to look up
|
||||
// rtype: the record type
|
||||
// return: id of this operation
|
||||
int jdns_query(jdns_session_t *s, const unsigned char *name, int rtype);
|
||||
|
||||
// jdns_cancel_query:
|
||||
// s: session
|
||||
// id: the operation id to cancel
|
||||
// return: nothing
|
||||
void jdns_cancel_query(jdns_session_t *s, int id);
|
||||
|
||||
// jdns_publish:
|
||||
// s: session
|
||||
// mode: JDNS_PUBLISH shared or unique
|
||||
// rec: the record data
|
||||
// return: id of this operation
|
||||
// note: supported record types: A, AAAA, SRV, CNAME, PTR, TXT, and HINFO.
|
||||
// if the published type is not one of these, raw rdata must be set.
|
||||
int jdns_publish(jdns_session_t *s, int mode, const jdns_rr_t *rec);
|
||||
|
||||
// jdns_update_publish:
|
||||
// s: session
|
||||
// id: the operation id to update
|
||||
// rec: the record data
|
||||
// return: nothing
|
||||
void jdns_update_publish(jdns_session_t *s, int id, const jdns_rr_t *rec);
|
||||
|
||||
// jdns_cancel_publish:
|
||||
// s: session
|
||||
// id: the operation id to cancel
|
||||
// return: nothing
|
||||
void jdns_cancel_publish(jdns_session_t *s, int id);
|
||||
|
||||
// jdns_step:
|
||||
// s: session
|
||||
// return: JDNS_STEP flags OR'd together
|
||||
int jdns_step(jdns_session_t *s);
|
||||
|
||||
// jdns_next_timer:
|
||||
// s: session
|
||||
// return: milliseconds until timeout
|
||||
int jdns_next_timer(jdns_session_t *s);
|
||||
|
||||
// jdns_set_handle_readable:
|
||||
// s: session
|
||||
// handle: handle that is now readable
|
||||
// return: nothing
|
||||
void jdns_set_handle_readable(jdns_session_t *s, int handle);
|
||||
|
||||
// jdns_set_handle_writable:
|
||||
// s: session
|
||||
// handle: handle that is now writable
|
||||
// return: nothing
|
||||
void jdns_set_handle_writable(jdns_session_t *s, int handle);
|
||||
|
||||
// jdns_next_event:
|
||||
// s: session
|
||||
// return: newly allocated event, or zero if none are ready
|
||||
jdns_event_t *jdns_next_event(jdns_session_t *s);
|
||||
|
||||
// jdns_system_dnsparams:
|
||||
// return: newly allocated dnsparams from the system
|
||||
jdns_dnsparams_t *jdns_system_dnsparams();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
27
iris-legacy/iris/irisnet/jdns/jdns.pri
Normal file
27
iris-legacy/iris/irisnet/jdns/jdns.pri
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# qmake project include file
|
||||
|
||||
QT *= network
|
||||
|
||||
windows:{
|
||||
LIBS += -lWs2_32 -lAdvapi32
|
||||
}
|
||||
unix:{
|
||||
#QMAKE_CFLAGS += -pedantic
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/jdns_packet.h \
|
||||
$$PWD/jdns_mdnsd.h \
|
||||
$$PWD/jdns_p.h \
|
||||
$$PWD/jdns.h \
|
||||
$$PWD/qjdns_sock.h \
|
||||
$$PWD/qjdns.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/jdns_util.c \
|
||||
$$PWD/jdns_packet.c \
|
||||
$$PWD/jdns_mdnsd.c \
|
||||
$$PWD/jdns_sys.c \
|
||||
$$PWD/jdns.c \
|
||||
$$PWD/qjdns_sock.cpp \
|
||||
$$PWD/qjdns.cpp
|
||||
9
iris-legacy/iris/irisnet/jdns/jdns.pro
Normal file
9
iris-legacy/iris/irisnet/jdns/jdns.pro
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
QT -= gui
|
||||
QT += network
|
||||
|
||||
include(jdns.pri)
|
||||
|
||||
SOURCES += \
|
||||
main.cpp
|
||||
1097
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.c
Normal file
1097
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.c
Normal file
File diff suppressed because it is too large
Load diff
120
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.h
Normal file
120
iris-legacy/iris/irisnet/jdns/jdns_mdnsd.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2005 Jeremie Miller
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_MDNSD_H
|
||||
#define JDNS_MDNSD_H
|
||||
|
||||
#include "jdns_p.h"
|
||||
|
||||
struct mytimeval
|
||||
{
|
||||
unsigned long int tv_sec; /* seconds */
|
||||
unsigned long int tv_usec; /* microseconds */
|
||||
};
|
||||
|
||||
typedef struct mdnsd_struct *mdnsd; // main daemon data
|
||||
typedef struct mdnsdr_struct *mdnsdr; // record entry
|
||||
// answer data
|
||||
typedef struct mdnsda_struct
|
||||
{
|
||||
unsigned char *name;
|
||||
unsigned short int type;
|
||||
unsigned long int ttl;
|
||||
unsigned long int real_ttl;
|
||||
unsigned short int rdlen;
|
||||
unsigned char *rdata;
|
||||
unsigned long int ip; // A
|
||||
unsigned char *rdname; // NS/CNAME/PTR/SRV
|
||||
struct { unsigned short int priority, weight, port; } srv; // SRV
|
||||
} *mdnsda;
|
||||
|
||||
///////////
|
||||
// Global functions
|
||||
//
|
||||
// create a new mdns daemon for the given class of names (usually 1) and maximum frame size
|
||||
mdnsd mdnsd_new(int class, int frame, int port, int (*time_now)(mdnsd d, void *arg), int (*rand_int)(mdnsd d, void *arg), void *arg);
|
||||
//
|
||||
// gracefully shutdown the daemon, use mdnsd_out() to get the last packets
|
||||
void mdnsd_shutdown(mdnsd d);
|
||||
//
|
||||
// flush all cached records (network/interface changed)
|
||||
void mdnsd_flush(mdnsd d);
|
||||
//
|
||||
// free given mdnsd (should have used mdnsd_shutdown() first!)
|
||||
void mdnsd_free(mdnsd d);
|
||||
//
|
||||
///////////
|
||||
|
||||
///////////
|
||||
// I/O functions
|
||||
//
|
||||
// incoming message from host (to be cached/processed)
|
||||
void mdnsd_in(mdnsd d, const jdns_packet_t *m, const jdns_response_t *resp, const jdns_address_t *addr, unsigned short int port);
|
||||
//
|
||||
// outgoing messge to be delivered to host, returns >0 if one was returned and m/ip/port set
|
||||
int mdnsd_out(mdnsd d, jdns_packet_t **m, jdns_address_t **addr, unsigned short int *port);
|
||||
//
|
||||
// returns the max wait-time until mdnsd_out() needs to be called again
|
||||
struct mytimeval *mdnsd_sleep(mdnsd d);
|
||||
//
|
||||
////////////
|
||||
|
||||
///////////
|
||||
// Q/A functions
|
||||
//
|
||||
// register a new query
|
||||
// answer(record, arg) is called whenever one is found/changes/expires (immediate or anytime after, mdnsda valid until ->ttl==0)
|
||||
// either answer returns -1, or another mdnsd_query with a NULL answer will remove/unregister this query
|
||||
void mdnsd_query(mdnsd d, char *host, int type, int (*answer)(mdnsda a, void *arg), void *arg);
|
||||
//
|
||||
// returns the first (if last == NULL) or next answer after last from the cache
|
||||
// mdnsda only valid until an I/O function is called
|
||||
mdnsda mdnsd_list(mdnsd d, char *host, int type, mdnsda last);
|
||||
//
|
||||
///////////
|
||||
|
||||
///////////
|
||||
// Publishing functions
|
||||
//
|
||||
// create a new unique record (try mdnsda_list first to make sure it's not used)
|
||||
// conflict(arg) called at any point when one is detected and unable to recover
|
||||
// after the first data is set_*(), any future changes effectively expire the old one and attempt to create a new unique record
|
||||
mdnsdr mdnsd_unique(mdnsd d, char *host, int type, long int ttl, void (*pubresult)(int result, char *host, int type, void *arg), void *arg);
|
||||
//
|
||||
// create a new shared record
|
||||
mdnsdr mdnsd_shared(mdnsd d, char *host, int type, long int ttl);
|
||||
//
|
||||
// de-list the given record
|
||||
void mdnsd_done(mdnsd d, mdnsdr r);
|
||||
//
|
||||
// these all set/update the data for the given record, nothing is published until they are called
|
||||
void mdnsd_set_raw(mdnsd d, mdnsdr r, char *data, int len);
|
||||
void mdnsd_set_host(mdnsd d, mdnsdr r, char *name);
|
||||
void mdnsd_set_ip(mdnsd d, mdnsdr r, unsigned long int ip);
|
||||
void mdnsd_set_srv(mdnsd d, mdnsdr r, int priority, int weight, int port, char *name);
|
||||
//
|
||||
///////////
|
||||
|
||||
|
||||
#endif
|
||||
83
iris-legacy/iris/irisnet/jdns/jdns_p.h
Normal file
83
iris-legacy/iris/irisnet/jdns/jdns_p.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_P_H
|
||||
#define JDNS_P_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
|
||||
# define JDNS_OS_WIN
|
||||
#else
|
||||
# define JDNS_OS_UNIX
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
|
||||
# define JDNS_OS_MAC
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_UNIX
|
||||
# include <unistd.h>
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "jdns.h"
|
||||
#include "jdns_packet.h"
|
||||
|
||||
// jdns_util.c
|
||||
void *jdns_alloc(int size);
|
||||
void *jdns_realloc(void *p, int size);
|
||||
void jdns_free(void *p);
|
||||
char *jdns_strdup(const char *s);
|
||||
unsigned char *jdns_copy_array(const unsigned char *src, int size);
|
||||
int jdns_domain_cmp(const unsigned char *a, const unsigned char *b);
|
||||
|
||||
int jdns_string_indexOf(const jdns_string_t *s, unsigned char c, int pos);
|
||||
jdns_stringlist_t *jdns_string_split(const jdns_string_t *s, unsigned char sep);
|
||||
|
||||
jdns_dnshost_t *jdns_dnshost_new();
|
||||
jdns_dnshost_t *jdns_dnshost_copy(const jdns_dnshost_t *a);
|
||||
void jdns_dnshost_delete(jdns_dnshost_t *a);
|
||||
jdns_dnshostlist_t *jdns_dnshostlist_new();
|
||||
jdns_dnshostlist_t *jdns_dnshostlist_copy(const jdns_dnshostlist_t *a);
|
||||
void jdns_dnshostlist_delete(jdns_dnshostlist_t *a);
|
||||
void jdns_dnshostlist_append(jdns_dnshostlist_t *a, const jdns_dnshost_t *host);
|
||||
|
||||
jdns_rr_t *jdns_rr_from_resource(const jdns_packet_resource_t *pr, const jdns_packet_t *ref);
|
||||
void jdns_response_remove_extra(jdns_response_t *r);
|
||||
void jdns_response_remove_answer(jdns_response_t *r, int pos);
|
||||
|
||||
#define alloc_type(type) (type *)jdns_alloc(sizeof(type))
|
||||
#define _ustrdup(str) (unsigned char *)jdns_strdup((const char *)str)
|
||||
#define _ustrlen(str) strlen((const char *)str)
|
||||
#define _ustrcmp(a, b) strcmp((const char *)a, (const char *)b)
|
||||
|
||||
#endif
|
||||
989
iris-legacy/iris/irisnet/jdns/jdns_packet.c
Normal file
989
iris-legacy/iris/irisnet/jdns/jdns_packet.c
Normal file
|
|
@ -0,0 +1,989 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* 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 "jdns_packet.h"
|
||||
|
||||
#include "jdns_p.h"
|
||||
|
||||
// jer's endian functions
|
||||
static unsigned short int net2short(const unsigned char **bufp)
|
||||
{
|
||||
unsigned short int i;
|
||||
i = **bufp;
|
||||
i <<= 8;
|
||||
i |= *(*bufp + 1);
|
||||
*bufp += 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned long int net2long(const unsigned char **bufp)
|
||||
{
|
||||
unsigned long int l;
|
||||
l = **bufp;
|
||||
l <<= 8;
|
||||
l |= *(*bufp + 1);
|
||||
l <<= 8;
|
||||
l |= *(*bufp + 2);
|
||||
l <<= 8;
|
||||
l |= *(*bufp + 3);
|
||||
*bufp += 4;
|
||||
return l;
|
||||
}
|
||||
|
||||
static void short2net(unsigned short int i, unsigned char **bufp)
|
||||
{
|
||||
*(*bufp + 1) = (unsigned char)i;
|
||||
i >>= 8;
|
||||
**bufp = (unsigned char)i;
|
||||
*bufp += 2;
|
||||
}
|
||||
|
||||
static void long2net(unsigned long int l, unsigned char **bufp)
|
||||
{
|
||||
*(*bufp + 3) = (unsigned char)l;
|
||||
l >>= 8;
|
||||
*(*bufp + 2) = (unsigned char)l;
|
||||
l >>= 8;
|
||||
*(*bufp + 1) = (unsigned char)l;
|
||||
l >>= 8;
|
||||
**bufp = (unsigned char)l;
|
||||
*bufp += 4;
|
||||
}
|
||||
|
||||
// label stuff
|
||||
typedef struct jdns_packet_label
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int offset;
|
||||
jdns_string_t *value;
|
||||
} jdns_packet_label_t;
|
||||
|
||||
static void jdns_packet_label_delete(jdns_packet_label_t *a);
|
||||
static jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a);
|
||||
|
||||
static jdns_packet_label_t *jdns_packet_label_new()
|
||||
{
|
||||
jdns_packet_label_t *a = JDNS_OBJECT_NEW(jdns_packet_label);
|
||||
a->offset = 0;
|
||||
a->value = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_label_t *jdns_packet_label_copy(const jdns_packet_label_t *a)
|
||||
{
|
||||
jdns_packet_label_t *c = jdns_packet_label_new();
|
||||
c->offset = a->offset;
|
||||
if(a->value)
|
||||
c->value = jdns_string_copy(a->value);
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_label_delete(jdns_packet_label_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->value);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
// gets an offset for decompression. does range and hop count checking also
|
||||
static int getoffset(const unsigned char *str, int refsize, int *hopsleft)
|
||||
{
|
||||
unsigned short int x;
|
||||
if(*hopsleft <= 0)
|
||||
return -1;
|
||||
--(*hopsleft);
|
||||
x = str[0] & 0x3f;
|
||||
x <<= 8;
|
||||
x |= str[1];
|
||||
// stay in bounds
|
||||
if(x >= refsize)
|
||||
return -1;
|
||||
return x;
|
||||
}
|
||||
|
||||
static int readlabel(const unsigned char *in, int insize, const unsigned char *ref, int refsize, int *_at, jdns_string_t **name)
|
||||
{
|
||||
int at;
|
||||
unsigned char out[255];
|
||||
int out_size;
|
||||
const unsigned char *label, *last;
|
||||
int hopped_yet;
|
||||
int hopsleft;
|
||||
int label_size;
|
||||
|
||||
at = *_at;
|
||||
|
||||
// stay in range
|
||||
if(at < 0 || at >= insize)
|
||||
return 0;
|
||||
|
||||
out_size = 0;
|
||||
label = in + at;
|
||||
hopped_yet = 0;
|
||||
last = in + insize;
|
||||
while(1)
|
||||
{
|
||||
// need a byte
|
||||
if(label + 1 > last)
|
||||
goto error;
|
||||
|
||||
// we make this a while loop instead of an 'if', in case
|
||||
// there's a pointer to a pointer. as a precaution,
|
||||
// we will hop no more than 8 times
|
||||
hopsleft = 8;
|
||||
while(*label & 0xc0)
|
||||
{
|
||||
int offset;
|
||||
|
||||
// need the next byte, too
|
||||
if(label + 2 > last)
|
||||
goto error;
|
||||
|
||||
offset = getoffset(label, refsize, &hopsleft);
|
||||
if(offset == -1)
|
||||
goto error;
|
||||
|
||||
label = ref + offset;
|
||||
if(!hopped_yet)
|
||||
{
|
||||
at += 2;
|
||||
hopped_yet = 1;
|
||||
last = ref + refsize;
|
||||
}
|
||||
|
||||
// need a byte
|
||||
if(label + 1 > last)
|
||||
goto error;
|
||||
}
|
||||
|
||||
label_size = *label & 0x3f;
|
||||
|
||||
// null label? then we're done
|
||||
if(label_size == 0)
|
||||
{
|
||||
if(!hopped_yet)
|
||||
++at;
|
||||
break;
|
||||
}
|
||||
|
||||
// enough source bytes? (length byte + length)
|
||||
if(label + label_size + 1 > last)
|
||||
goto error;
|
||||
|
||||
// enough dest bytes? (length + dot)
|
||||
if(out_size + label_size + 1 > 255)
|
||||
goto error;
|
||||
|
||||
memcpy(out + out_size, label + 1, label_size);
|
||||
out_size += label_size;
|
||||
out[out_size] = '.';
|
||||
++out_size;
|
||||
|
||||
if(!hopped_yet)
|
||||
at += label_size + 1;
|
||||
|
||||
label += label_size + 1;
|
||||
}
|
||||
|
||||
*_at = at;
|
||||
*name = jdns_string_new();
|
||||
jdns_string_set(*name, out, out_size);
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this function compares labels in label format:
|
||||
// [length] [value ...] [length] [value ...] [0]
|
||||
static int matchlabel(const unsigned char *a, int asize, const unsigned char *b, int bsize, const unsigned char *ref, int refsize, int ahopsleft, int bhopsleft)
|
||||
{
|
||||
int n, alen, blen, offset;
|
||||
|
||||
// same pointer?
|
||||
if(a == b)
|
||||
return 1;
|
||||
|
||||
if(asize < 1 || bsize < 1)
|
||||
return 0;
|
||||
|
||||
// always ensure we get called without a pointer
|
||||
if(*a & 0xc0)
|
||||
{
|
||||
if(asize < 2)
|
||||
return 0;
|
||||
offset = getoffset(a, refsize, &ahopsleft);
|
||||
if(offset == -1)
|
||||
return 0;
|
||||
return matchlabel(ref + offset, refsize - offset, b, bsize, ref, refsize, ahopsleft, bhopsleft);
|
||||
}
|
||||
if(*b & 0xc0)
|
||||
{
|
||||
if(bsize < 2)
|
||||
return 0;
|
||||
offset = getoffset(b, refsize, &bhopsleft);
|
||||
if(offset == -1)
|
||||
return 0;
|
||||
return matchlabel(a, asize, ref + offset, refsize - offset, ref, refsize, ahopsleft, bhopsleft);
|
||||
}
|
||||
|
||||
alen = *a & 0x3f;
|
||||
blen = *b & 0x3f;
|
||||
|
||||
// must be same length
|
||||
if(alen != blen)
|
||||
return 0;
|
||||
|
||||
// done?
|
||||
if(alen == 0)
|
||||
return 1;
|
||||
|
||||
// length byte + length + first byte of next label
|
||||
if(asize < alen + 2)
|
||||
return 0;
|
||||
if(bsize < blen + 2)
|
||||
return 0;
|
||||
|
||||
// compare the value
|
||||
for(n = 1; n < alen + 1; ++n)
|
||||
{
|
||||
if(a[n] != b[n])
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try next labels
|
||||
n = alen + 1;
|
||||
return matchlabel(a + n, asize - n, b + n, bsize - n, ref, refsize, ahopsleft, bhopsleft);
|
||||
}
|
||||
|
||||
int jdns_packet_name_isvalid(const unsigned char *name, int size)
|
||||
{
|
||||
int n, at, len;
|
||||
|
||||
// at least one byte, no larger than 254 (one byte is gained when
|
||||
// converting to a label, which has a 255 byte max)
|
||||
if(size < 1 || size > 254)
|
||||
return 0;
|
||||
|
||||
// last byte must be a dot
|
||||
if(name[size - 1] != '.')
|
||||
return 0;
|
||||
|
||||
// first byte can't be a dot if there are characters after
|
||||
if(size > 1 && name[0] == '.')
|
||||
return 0;
|
||||
|
||||
// each sublabel must be between 1 and 63 in length
|
||||
at = 0;
|
||||
while(1)
|
||||
{
|
||||
// search for dot or end
|
||||
for(n = at; n < size; ++n)
|
||||
{
|
||||
if(name[n] == '.')
|
||||
break;
|
||||
}
|
||||
// length of last one is always zero
|
||||
if(n >= size)
|
||||
break;
|
||||
|
||||
len = n - at;
|
||||
if(len < 1 || len > 63)
|
||||
return 0;
|
||||
at = n + 1; // skip over the dot
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// this function assumes label is pointing to a 255 byte buffer
|
||||
static int name_to_label(const jdns_string_t *name, unsigned char *label)
|
||||
{
|
||||
int n, i, at, len;
|
||||
|
||||
if(!jdns_packet_name_isvalid(name->data, name->size))
|
||||
return -1;
|
||||
|
||||
if(name->size == 1)
|
||||
{
|
||||
label[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
at = 0;
|
||||
i = 0;
|
||||
while(1)
|
||||
{
|
||||
// search for dot or end
|
||||
for(n = at; n < name->size; ++n)
|
||||
{
|
||||
if(name->data[n] == '.')
|
||||
break;
|
||||
}
|
||||
len = n - at;
|
||||
if(i + (len + 1) > 255) // length byte + length
|
||||
return 0;
|
||||
|
||||
label[i++] = len;
|
||||
memcpy(label + i, name->data + at, len);
|
||||
i += len;
|
||||
|
||||
if(n >= name->size) // end?
|
||||
break;
|
||||
at = n + 1; // skip over the dot
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// lookup list is made of jdns_packet_labels
|
||||
static int writelabel(const jdns_string_t *name, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
|
||||
{
|
||||
unsigned char label[255];
|
||||
int n, i, len;
|
||||
unsigned char *l;
|
||||
unsigned char *ref;
|
||||
int refsize;
|
||||
|
||||
len = name_to_label(name, label);
|
||||
if(len == -1)
|
||||
return 0;
|
||||
|
||||
ref = *bufp - at;
|
||||
refsize = at + left;
|
||||
for(n = 0; label[n]; n += label[n] + 1)
|
||||
{
|
||||
for(i = 0; i < lookup->count; ++i)
|
||||
{
|
||||
jdns_packet_label_t *pl = (jdns_packet_label_t *)lookup->item[i];
|
||||
|
||||
if(matchlabel(label + n, len - n, pl->value->data, pl->value->size, ref, refsize, 8, 8))
|
||||
{
|
||||
// set up a pointer right here, overwriting
|
||||
// the length byte and the first content
|
||||
// byte of this section within 'label'.
|
||||
// this is safe, because the length value
|
||||
// will always be greater than zero,
|
||||
// ensuring we have two bytes available to
|
||||
// use.
|
||||
l = label + n;
|
||||
short2net((unsigned short int)pl->offset, &l);
|
||||
label[n] |= 0xc0;
|
||||
len = n + 2; // cut things short
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(label[n] & 0xc0) // double loop, so break again
|
||||
break;
|
||||
}
|
||||
|
||||
if(left < len)
|
||||
return 0;
|
||||
|
||||
// copy into buffer, point there now
|
||||
memcpy(*bufp, label, len);
|
||||
l = *bufp;
|
||||
*bufp += len;
|
||||
|
||||
// for each new label, store its location for future compression
|
||||
for(n = 0; l[n]; n += l[n] + 1)
|
||||
{
|
||||
jdns_string_t *str;
|
||||
jdns_packet_label_t *pl;
|
||||
if(l[n] & 0xc0)
|
||||
break;
|
||||
|
||||
pl = jdns_packet_label_new();
|
||||
str = jdns_string_new();
|
||||
jdns_string_set(str, l + n, len - n);
|
||||
pl->offset = l + n - ref;
|
||||
pl->value = str;
|
||||
jdns_list_insert(lookup, pl, -1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet_write
|
||||
//----------------------------------------------------------------------------
|
||||
#define JDNS_PACKET_WRITE_RAW 0
|
||||
#define JDNS_PACKET_WRITE_NAME 1
|
||||
|
||||
struct jdns_packet_write
|
||||
{
|
||||
JDNS_OBJECT
|
||||
int type;
|
||||
jdns_string_t *value;
|
||||
};
|
||||
|
||||
void jdns_packet_write_delete(jdns_packet_write_t *a);
|
||||
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a);
|
||||
|
||||
jdns_packet_write_t *jdns_packet_write_new()
|
||||
{
|
||||
jdns_packet_write_t *a = JDNS_OBJECT_NEW(jdns_packet_write);
|
||||
a->type = 0;
|
||||
a->value = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_write_t *jdns_packet_write_copy(const jdns_packet_write_t *a)
|
||||
{
|
||||
jdns_packet_write_t *c = jdns_packet_write_new();
|
||||
c->type = a->type;
|
||||
if(a->value)
|
||||
c->value = jdns_string_copy(a->value);
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_write_delete(jdns_packet_write_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->value);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet_question
|
||||
//----------------------------------------------------------------------------
|
||||
jdns_packet_question_t *jdns_packet_question_new()
|
||||
{
|
||||
jdns_packet_question_t *a = JDNS_OBJECT_NEW(jdns_packet_question);
|
||||
a->qname = 0;
|
||||
a->qtype = 0;
|
||||
a->qclass = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a)
|
||||
{
|
||||
jdns_packet_question_t *c = jdns_packet_question_new();
|
||||
if(a->qname)
|
||||
c->qname = jdns_string_copy(a->qname);
|
||||
c->qtype = a->qtype;
|
||||
c->qclass = a->qclass;
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_question_delete(jdns_packet_question_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->qname);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet_resource
|
||||
//----------------------------------------------------------------------------
|
||||
jdns_packet_resource_t *jdns_packet_resource_new()
|
||||
{
|
||||
jdns_packet_resource_t *a = JDNS_OBJECT_NEW(jdns_packet_resource);
|
||||
a->qname = 0;
|
||||
a->qtype = 0;
|
||||
a->qclass = 0;
|
||||
a->ttl = 0;
|
||||
a->rdlength = 0;
|
||||
a->rdata = 0;
|
||||
|
||||
a->writelog = jdns_list_new();
|
||||
a->writelog->valueList = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a)
|
||||
{
|
||||
jdns_packet_resource_t *c = jdns_packet_resource_new();
|
||||
if(a->qname)
|
||||
c->qname = jdns_string_copy(a->qname);
|
||||
c->qtype = a->qtype;
|
||||
c->qclass = a->qclass;
|
||||
c->ttl = a->ttl;
|
||||
c->rdlength = a->rdlength;
|
||||
c->rdata = jdns_copy_array(a->rdata, a->rdlength);
|
||||
|
||||
jdns_list_delete(c->writelog);
|
||||
c->writelog = jdns_list_copy(a->writelog);
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_resource_delete(jdns_packet_resource_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_string_delete(a->qname);
|
||||
if(a->rdata)
|
||||
jdns_free(a->rdata);
|
||||
jdns_list_delete(a->writelog);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size)
|
||||
{
|
||||
jdns_packet_write_t *write = jdns_packet_write_new();
|
||||
write->type = JDNS_PACKET_WRITE_RAW;
|
||||
write->value = jdns_string_new();
|
||||
jdns_string_set(write->value, data, size);
|
||||
jdns_list_insert_value(a->writelog, write, -1);
|
||||
jdns_packet_write_delete(write);
|
||||
}
|
||||
|
||||
void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name)
|
||||
{
|
||||
jdns_packet_write_t *write = jdns_packet_write_new();
|
||||
write->type = JDNS_PACKET_WRITE_NAME;
|
||||
write->value = jdns_string_copy(name);
|
||||
jdns_list_insert_value(a->writelog, write, -1);
|
||||
jdns_packet_write_delete(write);
|
||||
}
|
||||
|
||||
int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name)
|
||||
{
|
||||
return readlabel(a->rdata, a->rdlength, p->raw_data, p->raw_size, at, name);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// jdns_packet
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// note: both process_qsection and process_rrsection modify the 'dest' list,
|
||||
// even if later items cause an error. this turns out to be convenient
|
||||
// for handling truncated dns packets
|
||||
|
||||
static int process_qsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
|
||||
{
|
||||
int n;
|
||||
int offset, at;
|
||||
jdns_string_t *name = 0;
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = *bufp;
|
||||
for(n = 0; n < count; ++n)
|
||||
{
|
||||
jdns_packet_question_t *q;
|
||||
|
||||
offset = buf - data;
|
||||
at = 0;
|
||||
|
||||
if(!readlabel(data + offset, size - offset, data, size, &at, &name))
|
||||
goto error;
|
||||
|
||||
offset += at;
|
||||
|
||||
// need 4 more bytes
|
||||
if(size - offset < 4)
|
||||
goto error;
|
||||
|
||||
buf = data + offset;
|
||||
|
||||
q = jdns_packet_question_new();
|
||||
q->qname = name;
|
||||
name = 0;
|
||||
q->qtype = net2short(&buf);
|
||||
q->qclass = net2short(&buf);
|
||||
|
||||
jdns_list_insert_value(dest, q, -1);
|
||||
jdns_packet_question_delete(q);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_string_delete(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_rrsection(jdns_list_t *dest, int count, const unsigned char *data, int size, const unsigned char **bufp)
|
||||
{
|
||||
int n;
|
||||
int offset, at;
|
||||
jdns_string_t *name = 0;
|
||||
const unsigned char *buf;
|
||||
|
||||
buf = *bufp;
|
||||
for(n = 0; n < count; ++n)
|
||||
{
|
||||
jdns_packet_resource_t *r;
|
||||
|
||||
offset = buf - data;
|
||||
at = 0;
|
||||
|
||||
if(!readlabel(data + offset, size - offset, data, size, &at, &name))
|
||||
goto error;
|
||||
|
||||
offset += at;
|
||||
|
||||
// need 10 more bytes
|
||||
if(offset + 10 > size)
|
||||
goto error;
|
||||
|
||||
buf = data + offset;
|
||||
|
||||
r = jdns_packet_resource_new();
|
||||
r->qname = name;
|
||||
name = 0;
|
||||
r->qtype = net2short(&buf);
|
||||
r->qclass = net2short(&buf);
|
||||
r->ttl = net2long(&buf);
|
||||
r->rdlength = net2short(&buf);
|
||||
|
||||
offset = buf - data;
|
||||
|
||||
// make sure we have enough for the rdata
|
||||
if(size - offset < r->rdlength)
|
||||
{
|
||||
jdns_packet_resource_delete(r);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r->rdata = jdns_copy_array(buf, r->rdlength);
|
||||
buf += r->rdlength;
|
||||
|
||||
jdns_list_insert_value(dest, r, -1);
|
||||
jdns_packet_resource_delete(r);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_string_delete(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_qsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
|
||||
{
|
||||
unsigned char *buf, *start, *last;
|
||||
int n;
|
||||
|
||||
buf = *bufp;
|
||||
start = buf - at;
|
||||
last = buf + left;
|
||||
for(n = 0; n < src->count; ++n)
|
||||
{
|
||||
jdns_packet_question_t *q = (jdns_packet_question_t *)src->item[n];
|
||||
|
||||
if(!writelabel(q->qname, buf - start, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
|
||||
if(buf + 4 > last)
|
||||
goto error;
|
||||
|
||||
short2net(q->qtype, &buf);
|
||||
short2net(q->qclass, &buf);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_rrsection(const jdns_list_t *src, int at, int left, unsigned char **bufp, jdns_list_t *lookup)
|
||||
{
|
||||
unsigned char *buf, *start, *last, *rdlengthp;
|
||||
int n, i, rdlength;
|
||||
|
||||
buf = *bufp;
|
||||
start = buf - at;
|
||||
last = buf + left;
|
||||
for(n = 0; n < src->count; ++n)
|
||||
{
|
||||
jdns_packet_resource_t *r = (jdns_packet_resource_t *)src->item[n];
|
||||
|
||||
if(!writelabel(r->qname, buf - start, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
|
||||
if(buf + 10 > last)
|
||||
goto error;
|
||||
|
||||
short2net(r->qtype, &buf);
|
||||
short2net(r->qclass, &buf);
|
||||
long2net(r->ttl, &buf);
|
||||
|
||||
// skip over rdlength
|
||||
rdlengthp = buf;
|
||||
buf += 2;
|
||||
|
||||
// play write log
|
||||
rdlength = 0;
|
||||
for(i = 0; i < r->writelog->count; ++i)
|
||||
{
|
||||
jdns_packet_write_t *write = (jdns_packet_write_t *)r->writelog->item[i];
|
||||
if(write->type == JDNS_PACKET_WRITE_RAW)
|
||||
{
|
||||
if(buf + write->value->size > last)
|
||||
goto error;
|
||||
|
||||
memcpy(buf, write->value->data, write->value->size);
|
||||
buf += write->value->size;
|
||||
}
|
||||
else // JDNS_PACKET_WRITE_NAME
|
||||
{
|
||||
if(!writelabel(write->value, buf - start, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
i = buf - rdlengthp; // should be rdata size + 2
|
||||
short2net((unsigned short int)(i - 2), &rdlengthp);
|
||||
}
|
||||
|
||||
*bufp = buf;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
return 0;
|
||||
}
|
||||
|
||||
jdns_packet_t *jdns_packet_new()
|
||||
{
|
||||
jdns_packet_t *a = JDNS_OBJECT_NEW(jdns_packet);
|
||||
a->id = 0;
|
||||
a->opts.qr = 0;
|
||||
a->opts.opcode = 0;
|
||||
a->opts.aa = 0;
|
||||
a->opts.tc = 0;
|
||||
a->opts.rd = 0;
|
||||
a->opts.ra = 0;
|
||||
a->opts.z = 0;
|
||||
a->opts.rcode = 0;
|
||||
|
||||
a->questions = jdns_list_new();
|
||||
a->answerRecords = jdns_list_new();
|
||||
a->authorityRecords = jdns_list_new();
|
||||
a->additionalRecords = jdns_list_new();
|
||||
|
||||
a->questions->valueList = 1;
|
||||
a->answerRecords->valueList = 1;
|
||||
a->authorityRecords->valueList = 1;
|
||||
a->additionalRecords->valueList = 1;
|
||||
|
||||
a->fully_parsed = 0;
|
||||
|
||||
a->raw_size = 0;
|
||||
a->raw_data = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a)
|
||||
{
|
||||
jdns_packet_t *c = jdns_packet_new();
|
||||
c->id = a->id;
|
||||
c->opts.qr = a->opts.qr;
|
||||
c->opts.opcode = a->opts.opcode;
|
||||
c->opts.aa = a->opts.aa;
|
||||
c->opts.tc = a->opts.tc;
|
||||
c->opts.rd = a->opts.rd;
|
||||
c->opts.ra = a->opts.ra;
|
||||
c->opts.z = a->opts.z;
|
||||
c->opts.rcode = a->opts.rcode;
|
||||
|
||||
jdns_list_delete(c->questions);
|
||||
jdns_list_delete(c->answerRecords);
|
||||
jdns_list_delete(c->authorityRecords);
|
||||
jdns_list_delete(c->additionalRecords);
|
||||
c->questions = jdns_list_copy(a->questions);
|
||||
c->answerRecords = jdns_list_copy(a->answerRecords);
|
||||
c->authorityRecords = jdns_list_copy(a->authorityRecords);
|
||||
c->additionalRecords = jdns_list_copy(a->additionalRecords);
|
||||
|
||||
c->fully_parsed = a->fully_parsed;
|
||||
|
||||
c->raw_size = a->raw_size;
|
||||
c->raw_data = jdns_copy_array(a->raw_data, a->raw_size);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void jdns_packet_delete(jdns_packet_t *a)
|
||||
{
|
||||
if(!a)
|
||||
return;
|
||||
jdns_list_delete(a->questions);
|
||||
jdns_list_delete(a->answerRecords);
|
||||
jdns_list_delete(a->authorityRecords);
|
||||
jdns_list_delete(a->additionalRecords);
|
||||
if(a->raw_data)
|
||||
jdns_free(a->raw_data);
|
||||
jdns_object_free(a);
|
||||
}
|
||||
|
||||
int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size)
|
||||
{
|
||||
jdns_packet_t *tmp = 0;
|
||||
const unsigned char *buf;
|
||||
|
||||
// need at least some data
|
||||
if(!data || size == 0)
|
||||
return 0;
|
||||
|
||||
// header (id + options + item counts) is 12 bytes
|
||||
if(size < 12)
|
||||
goto error;
|
||||
|
||||
tmp = jdns_packet_new();
|
||||
buf = data;
|
||||
|
||||
// id
|
||||
tmp->id = net2short(&buf);
|
||||
|
||||
// options
|
||||
if(buf[0] & 0x80) // qr is bit 7
|
||||
tmp->opts.qr = 1;
|
||||
tmp->opts.opcode = (buf[0] & 0x78) >> 3; // opcode is bits 6,5,4,3
|
||||
if(buf[0] & 0x04) // aa is bit 2
|
||||
tmp->opts.aa = 1;
|
||||
if(buf[0] & 0x02) // tc is bit 1
|
||||
tmp->opts.tc = 1;
|
||||
if(buf[0] & 0x01) // rd is bit 0
|
||||
tmp->opts.rd = 1;
|
||||
if(buf[1] & 0x80) // ra is bit 7 (second byte)
|
||||
tmp->opts.ra = 1;
|
||||
tmp->opts.z = (buf[1] & 0x70) >> 4; // z is bits 6,5,4
|
||||
tmp->opts.rcode = buf[1] & 0x0f; // rcode is bits 3,2,1,0
|
||||
buf += 2;
|
||||
|
||||
// item counts
|
||||
tmp->qdcount = net2short(&buf);
|
||||
tmp->ancount = net2short(&buf);
|
||||
tmp->nscount = net2short(&buf);
|
||||
tmp->arcount = net2short(&buf);
|
||||
|
||||
// if these fail, we don't count them as errors, since the packet
|
||||
// might have been truncated
|
||||
if(!process_qsection(tmp->questions, tmp->qdcount, data, size, &buf))
|
||||
goto skip;
|
||||
if(!process_rrsection(tmp->answerRecords, tmp->ancount, data, size, &buf))
|
||||
goto skip;
|
||||
if(!process_rrsection(tmp->authorityRecords, tmp->nscount, data, size, &buf))
|
||||
goto skip;
|
||||
if(!process_rrsection(tmp->additionalRecords, tmp->arcount, data, size, &buf))
|
||||
goto skip;
|
||||
|
||||
tmp->fully_parsed = 1;
|
||||
|
||||
skip:
|
||||
// keep the raw data for reference during rdata parsing
|
||||
tmp->raw_size = size;
|
||||
tmp->raw_data = jdns_copy_array(data, size);
|
||||
|
||||
*a = tmp;
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_packet_delete(tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jdns_packet_export(jdns_packet_t *a, int maxsize)
|
||||
{
|
||||
unsigned char *block = 0;
|
||||
unsigned char *buf, *last;
|
||||
unsigned char c;
|
||||
int size;
|
||||
jdns_list_t *lookup = 0; // to hold jdns_packet_label_t
|
||||
|
||||
// clear out any existing raw data before we begin
|
||||
if(a->raw_data)
|
||||
{
|
||||
jdns_free(a->raw_data);
|
||||
a->raw_data = 0;
|
||||
a->raw_size = 0;
|
||||
}
|
||||
|
||||
// preallocate
|
||||
size = maxsize;
|
||||
block = (unsigned char *)jdns_alloc(size);
|
||||
memset(block, 0, size);
|
||||
|
||||
buf = block;
|
||||
last = block + size;
|
||||
|
||||
if(size < 12)
|
||||
goto error;
|
||||
|
||||
short2net(a->id, &buf);
|
||||
if(a->opts.qr)
|
||||
buf[0] |= 0x80;
|
||||
c = (unsigned char)a->opts.opcode;
|
||||
buf[0] |= c << 3;
|
||||
if(a->opts.aa)
|
||||
buf[0] |= 0x04;
|
||||
if(a->opts.tc)
|
||||
buf[0] |= 0x02;
|
||||
if(a->opts.rd)
|
||||
buf[0] |= 0x01;
|
||||
if(a->opts.ra)
|
||||
buf[1] |= 0x80;
|
||||
c = (unsigned char)a->opts.z;
|
||||
buf[1] |= c << 4;
|
||||
c = (unsigned char)a->opts.rcode;
|
||||
buf[1] |= c;
|
||||
buf += 2;
|
||||
short2net((unsigned short int)a->questions->count, &buf);
|
||||
short2net((unsigned short int)a->answerRecords->count, &buf);
|
||||
short2net((unsigned short int)a->authorityRecords->count, &buf);
|
||||
short2net((unsigned short int)a->additionalRecords->count, &buf);
|
||||
|
||||
// append sections
|
||||
lookup = jdns_list_new();
|
||||
lookup->autoDelete = 1;
|
||||
|
||||
if(!append_qsection(a->questions, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
if(!append_rrsection(a->answerRecords, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
if(!append_rrsection(a->authorityRecords, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
if(!append_rrsection(a->additionalRecords, buf - block, last - buf, &buf, lookup))
|
||||
goto error;
|
||||
|
||||
// done with all sections
|
||||
jdns_list_delete(lookup);
|
||||
|
||||
// condense
|
||||
size = buf - block;
|
||||
block = (unsigned char *)jdns_realloc(block, size);
|
||||
|
||||
// finalize
|
||||
a->qdcount = a->questions->count;
|
||||
a->ancount = a->answerRecords->count;
|
||||
a->nscount = a->authorityRecords->count;
|
||||
a->arcount = a->additionalRecords->count;
|
||||
a->raw_data = block;
|
||||
a->raw_size = size;
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
jdns_list_delete(lookup);
|
||||
if(block)
|
||||
jdns_free(block);
|
||||
return 0;
|
||||
}
|
||||
116
iris-legacy/iris/irisnet/jdns/jdns_packet.h
Normal file
116
iris-legacy/iris/irisnet/jdns/jdns_packet.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef JDNS_PACKET_H
|
||||
#define JDNS_PACKET_H
|
||||
|
||||
#include "jdns.h"
|
||||
|
||||
// -- howto --
|
||||
//
|
||||
// writing packets:
|
||||
// 1) call jdns_packet_new()
|
||||
// 2) populate the jdns_packet_t structure, using the functions
|
||||
// as necessary
|
||||
// 3) call jdns_packet_export() to populate the raw data of the packet
|
||||
//
|
||||
// reading packets:
|
||||
// 1) call jdns_packet_new()
|
||||
// 2) call jdns_packet_import() with the raw data
|
||||
// 3) the jdns_packet_t structure is now populated
|
||||
//
|
||||
// IMPORTANT: all names must be valid. that is, ending in a dot character
|
||||
|
||||
int jdns_packet_name_isvalid(const unsigned char *name, int size); // 0 if not valid
|
||||
|
||||
typedef struct jdns_packet_question
|
||||
{
|
||||
JDNS_OBJECT
|
||||
jdns_string_t *qname;
|
||||
unsigned short int qtype, qclass;
|
||||
} jdns_packet_question_t;
|
||||
|
||||
jdns_packet_question_t *jdns_packet_question_new();
|
||||
jdns_packet_question_t *jdns_packet_question_copy(const jdns_packet_question_t *a);
|
||||
void jdns_packet_question_delete(jdns_packet_question_t *a);
|
||||
|
||||
typedef struct jdns_packet_write jdns_packet_write_t;
|
||||
typedef struct jdns_packet jdns_packet_t;
|
||||
|
||||
typedef struct jdns_packet_resource
|
||||
{
|
||||
JDNS_OBJECT
|
||||
jdns_string_t *qname;
|
||||
unsigned short int qtype, qclass;
|
||||
unsigned long int ttl;
|
||||
unsigned short int rdlength;
|
||||
unsigned char *rdata;
|
||||
|
||||
// private
|
||||
jdns_list_t *writelog; // jdns_packet_write_t
|
||||
} jdns_packet_resource_t;
|
||||
|
||||
jdns_packet_resource_t *jdns_packet_resource_new();
|
||||
jdns_packet_resource_t *jdns_packet_resource_copy(const jdns_packet_resource_t *a);
|
||||
void jdns_packet_resource_delete(jdns_packet_resource_t *a);
|
||||
void jdns_packet_resource_add_bytes(jdns_packet_resource_t *a, const unsigned char *data, int size);
|
||||
void jdns_packet_resource_add_name(jdns_packet_resource_t *a, const jdns_string_t *name);
|
||||
int jdns_packet_resource_read_name(const jdns_packet_resource_t *a, const jdns_packet_t *p, int *at, jdns_string_t **name);
|
||||
|
||||
struct jdns_packet
|
||||
{
|
||||
JDNS_OBJECT
|
||||
unsigned short int id;
|
||||
struct
|
||||
{
|
||||
unsigned short qr, opcode, aa, tc, rd, ra, z, rcode;
|
||||
} opts;
|
||||
|
||||
// item counts as specified by the packet. do not use these
|
||||
// for iteration over the item lists, since they can be wrong
|
||||
// if the packet is truncated.
|
||||
int qdcount, ancount, nscount, arcount;
|
||||
|
||||
// value lists
|
||||
jdns_list_t *questions; // jdns_packet_question_t
|
||||
jdns_list_t *answerRecords; // jdns_packet_resource_t
|
||||
jdns_list_t *authorityRecords; // jdns_packet_resource_t
|
||||
jdns_list_t *additionalRecords; // jdns_packet_resource_t
|
||||
|
||||
// since dns packets are allowed to be truncated, it is possible
|
||||
// for a packet to not get fully parsed yet still be considered
|
||||
// successfully parsed. this flag means the packet was fully
|
||||
// parsed also.
|
||||
int fully_parsed;
|
||||
|
||||
int raw_size;
|
||||
unsigned char *raw_data;
|
||||
};
|
||||
|
||||
jdns_packet_t *jdns_packet_new();
|
||||
jdns_packet_t *jdns_packet_copy(const jdns_packet_t *a);
|
||||
void jdns_packet_delete(jdns_packet_t *a);
|
||||
int jdns_packet_import(jdns_packet_t **a, const unsigned char *data, int size); // 0 on fail
|
||||
int jdns_packet_export(jdns_packet_t *a, int maxsize); // 0 on fail
|
||||
|
||||
#endif
|
||||
822
iris-legacy/iris/irisnet/jdns/jdns_sys.c
Normal file
822
iris-legacy/iris/irisnet/jdns/jdns_sys.c
Normal file
|
|
@ -0,0 +1,822 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
this code probes the system for dns settings. blah.
|
||||
|
||||
q3dns strategies
|
||||
----------------
|
||||
|
||||
windows:
|
||||
|
||||
domain name, name server, "search list" found in windows registry here:
|
||||
|
||||
HKEY_LOCAL_MACHINE
|
||||
System\CurrentControlSet\Services\Tcpip\Parameters <-- win nt+
|
||||
System\CurrentControlSet\Services\VxD\MSTCP <-- win 98
|
||||
|
||||
for domain, try DhcpDomain else Domain
|
||||
for name servers, try DhcpNameServer, else NameServer
|
||||
for search list, try SearchList
|
||||
|
||||
iphlpapi.dll : GetNetworkParams(PFIXED_INFO, PULONG);
|
||||
|
||||
info->DomainName
|
||||
info->DnsServerList (if not null, use it, and loop through ->Next until
|
||||
null)
|
||||
no search list
|
||||
|
||||
first try getnetworkparams. if that fails, try the nt regkey then the 98
|
||||
regkey. it seems that search list can only come from the registry, so
|
||||
maybe we need to grab that entry even if getnetworkparams works.
|
||||
|
||||
in the case of the registry, the nameserver and searchlist entries are
|
||||
delimited by spaces on win nt and commas on win 98. probably a good
|
||||
idea to simplify white space first (chop away space at start and end,
|
||||
reduce all sections of spaces to one char). also, lowercase the search
|
||||
list.
|
||||
|
||||
qt doesn't read the hosts file on windows. this might be a good idea, but
|
||||
probably not worth it.
|
||||
|
||||
unix:
|
||||
|
||||
read /etc/resolv.conf manually:
|
||||
for each line, split at spaces
|
||||
if the first item is "nameserver", then there should be an IP address
|
||||
following it. note: may contain mixed ipv4 and ipv6 addresses
|
||||
if the first item is "search", all other items are added to the domain
|
||||
list
|
||||
if the first item is "domain", then the next item should be added to the
|
||||
domain list.
|
||||
do case-insensitive matching for the item types
|
||||
for search/domain, the items are in the 8-bit system locale
|
||||
|
||||
info can also be fetched using system calls. we use the res_* stuff here.
|
||||
first we should detect for a "modern res api". this is available from
|
||||
glibc 2.3 and onward. use the following scheme to check for it:
|
||||
|
||||
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2)
|
||||
&& (__GLIBC_MINOR__ >= 3)))
|
||||
// modern res api
|
||||
#endif
|
||||
|
||||
on mac we should look up res_init in the system library. see:
|
||||
qt_mac_resolve_sys(RTLD_NEXT, "res_init"); for a hint.
|
||||
otherwise we can just use res_init() straight.
|
||||
|
||||
under a modern res api, we do:
|
||||
struct __res_state res;
|
||||
res_ninit(&res);
|
||||
otherwise, we simply call res_init(). for the modern api, we use the "res"
|
||||
struct that we made. otherwise, we use the global "_res" struct.
|
||||
|
||||
read the res struct to obtain the name servers, search list, and domain.
|
||||
lowercase the search list and domain.
|
||||
|
||||
qt tries the file, and if that fails it tries the syscalls. we may want to
|
||||
do the syscalls first, or even just do both all the time.
|
||||
|
||||
read /etc/hosts manually:
|
||||
for each line
|
||||
if there is a '#' character in the line, remove it and everything to
|
||||
the right
|
||||
simplify white space
|
||||
convert to lowercase
|
||||
split the line at spaces
|
||||
first item is the ip address
|
||||
all remaining items are hostnames
|
||||
|
||||
note: these hosts could also be used for reverse-dns too
|
||||
note2: Windows has a hosts file as well (like C:\WINDOWS\hosts)
|
||||
*/
|
||||
|
||||
#include "jdns_p.h"
|
||||
|
||||
#ifdef JDNS_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_UNIX
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/nameser.h>
|
||||
# include <resolv.h>
|
||||
# include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#define string_indexOf jdns_string_indexOf
|
||||
#define string_split jdns_string_split
|
||||
|
||||
static int char_isspace(unsigned char c)
|
||||
{
|
||||
if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *string_getnextword(unsigned char *in, int size, int pos, int *newpos)
|
||||
{
|
||||
int n;
|
||||
int at;
|
||||
int len;
|
||||
unsigned char *out;
|
||||
|
||||
at = pos;
|
||||
|
||||
// skip any space at the start
|
||||
while(at < size && char_isspace(in[at]))
|
||||
++at;
|
||||
|
||||
// all space? no word then
|
||||
if(at >= size)
|
||||
return 0;
|
||||
|
||||
// skip until a space or end
|
||||
n = at;
|
||||
while(n < size && !char_isspace(in[n]))
|
||||
++n;
|
||||
len = n - at;
|
||||
|
||||
// allocate length + zero byte
|
||||
out = (unsigned char *)jdns_alloc(len + 1);
|
||||
if(!out)
|
||||
return 0;
|
||||
memcpy(out, in + at, len);
|
||||
out[len] = 0;
|
||||
*newpos = at + len;
|
||||
return out;
|
||||
}
|
||||
|
||||
static jdns_string_t *string_simplify(const jdns_string_t *in)
|
||||
{
|
||||
int n;
|
||||
int pos;
|
||||
int total;
|
||||
unsigned char *out;
|
||||
int outlen;
|
||||
jdns_string_t *outstr;
|
||||
jdns_stringlist_t *wordlist;
|
||||
|
||||
// gather words and total of lengths
|
||||
pos = 0;
|
||||
total = 0;
|
||||
wordlist = jdns_stringlist_new();
|
||||
while(1)
|
||||
{
|
||||
jdns_string_t *word;
|
||||
unsigned char *str = string_getnextword(in->data, in->size, pos, &pos);
|
||||
if(!str)
|
||||
break;
|
||||
word = jdns_string_new();
|
||||
jdns_string_set_cstr(word, (char *)str);
|
||||
jdns_free(str);
|
||||
jdns_stringlist_append(wordlist, word);
|
||||
total += word->size;
|
||||
jdns_string_delete(word);
|
||||
}
|
||||
|
||||
if(total == 0)
|
||||
{
|
||||
jdns_stringlist_delete(wordlist);
|
||||
|
||||
outstr = jdns_string_new();
|
||||
jdns_string_set_cstr(outstr, "");
|
||||
return outstr;
|
||||
}
|
||||
|
||||
// we need to allocate space for total lengths and wordcount-1 spaces
|
||||
outlen = total + (wordlist->count - 1);
|
||||
out = (unsigned char *)jdns_alloc(outlen);
|
||||
|
||||
// lay out the words
|
||||
pos = 0;
|
||||
for(n = 0; n < wordlist->count; ++n)
|
||||
{
|
||||
unsigned char *data = wordlist->item[n]->data;
|
||||
int size = wordlist->item[n]->size;
|
||||
memcpy(out + pos, data, size);
|
||||
pos += size;
|
||||
|
||||
// if this is not the last word, append a space
|
||||
if(n + 1 < wordlist->count)
|
||||
out[pos++] = ' ';
|
||||
}
|
||||
jdns_stringlist_delete(wordlist);
|
||||
|
||||
outstr = jdns_string_new();
|
||||
jdns_string_set(outstr, out, outlen);
|
||||
jdns_free(out);
|
||||
return outstr;
|
||||
}
|
||||
|
||||
static jdns_string_t *string_tolower(const jdns_string_t *in)
|
||||
{
|
||||
int n;
|
||||
jdns_string_t *out = jdns_string_copy(in);
|
||||
for(n = 0; n < out->size; ++n)
|
||||
out->data[n] = tolower(out->data[n]);
|
||||
return out;
|
||||
}
|
||||
|
||||
static jdns_string_t *file_nextline(FILE *f)
|
||||
{
|
||||
int at, size;
|
||||
unsigned char *buf;
|
||||
jdns_string_t *str;
|
||||
|
||||
size = 1023;
|
||||
buf = (unsigned char *)jdns_alloc(size);
|
||||
at = 0;
|
||||
while(1)
|
||||
{
|
||||
unsigned char c = fgetc(f);
|
||||
if(feof(f))
|
||||
{
|
||||
jdns_free(buf);
|
||||
return 0;
|
||||
}
|
||||
if(c == '\n')
|
||||
break;
|
||||
if(c == '\r')
|
||||
continue;
|
||||
if(at < 1023)
|
||||
buf[at++] = c;
|
||||
}
|
||||
|
||||
str = jdns_string_new();
|
||||
jdns_string_set(str, buf, at);
|
||||
jdns_free(buf);
|
||||
return str;
|
||||
}
|
||||
|
||||
static jdns_dnshostlist_t *read_hosts_file(const char *path)
|
||||
{
|
||||
jdns_dnshostlist_t *out;
|
||||
FILE *f;
|
||||
jdns_string_t *line, *simp;
|
||||
jdns_stringlist_t *parts;
|
||||
jdns_address_t *addr;
|
||||
int n;
|
||||
|
||||
out = jdns_dnshostlist_new();
|
||||
|
||||
f = fopen(path, "r");
|
||||
if(!f)
|
||||
return out;
|
||||
while(1)
|
||||
{
|
||||
line = file_nextline(f);
|
||||
if(!line)
|
||||
break;
|
||||
|
||||
// truncate at comment
|
||||
n = string_indexOf(line, '#', 0);
|
||||
if(n != -1)
|
||||
{
|
||||
line->size = n;
|
||||
line->data[n] = 0;
|
||||
}
|
||||
|
||||
simp = string_simplify(line);
|
||||
jdns_string_delete(line);
|
||||
|
||||
parts = string_split(simp, ' ');
|
||||
jdns_string_delete(simp);
|
||||
|
||||
if(parts->count < 2)
|
||||
{
|
||||
jdns_stringlist_delete(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = jdns_address_new();
|
||||
if(!jdns_address_set_cstr(addr, (const char *)parts->item[0]->data))
|
||||
{
|
||||
jdns_address_delete(addr);
|
||||
jdns_stringlist_delete(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
for(n = 1; n < parts->count; ++n)
|
||||
{
|
||||
jdns_dnshost_t *h = jdns_dnshost_new();
|
||||
h->name = jdns_string_copy(parts->item[n]);
|
||||
h->address = jdns_address_copy(addr);
|
||||
jdns_dnshostlist_append(out, h);
|
||||
jdns_dnshost_delete(h);
|
||||
}
|
||||
|
||||
jdns_address_delete(addr);
|
||||
jdns_stringlist_delete(parts);
|
||||
}
|
||||
fclose(f);
|
||||
return out;
|
||||
}
|
||||
|
||||
static void apply_hosts_file(jdns_dnsparams_t *a, const char *path)
|
||||
{
|
||||
int n;
|
||||
jdns_dnshostlist_t *list;
|
||||
|
||||
list = read_hosts_file(path);
|
||||
for(n = 0; n < list->count; ++n)
|
||||
jdns_dnshostlist_append(a->hosts, list->item[n]);
|
||||
jdns_dnshostlist_delete(list);
|
||||
}
|
||||
|
||||
static int dnsparams_have_domain(const jdns_dnsparams_t *a, const jdns_string_t *domain)
|
||||
{
|
||||
int n;
|
||||
for(n = 0; n < a->domains->count; ++n)
|
||||
{
|
||||
jdns_string_t *str = a->domains->item[n];
|
||||
if(strcmp((const char *)str->data, (const char *)domain->data) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef JDNS_OS_WIN
|
||||
|
||||
// from Microsoft IPTypes.h
|
||||
#ifndef IP_TYPES_INCLUDED
|
||||
#define MAX_HOSTNAME_LEN 128
|
||||
#define MAX_DOMAIN_NAME_LEN 128
|
||||
#define MAX_SCOPE_ID_LEN 256
|
||||
typedef struct {
|
||||
char String[4 * 4];
|
||||
} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
|
||||
typedef struct _IP_ADDR_STRING {
|
||||
struct _IP_ADDR_STRING* Next;
|
||||
IP_ADDRESS_STRING IpAddress;
|
||||
IP_MASK_STRING IpMask;
|
||||
DWORD Context;
|
||||
} IP_ADDR_STRING, *PIP_ADDR_STRING;
|
||||
typedef struct {
|
||||
char HostName[MAX_HOSTNAME_LEN + 4] ;
|
||||
char DomainName[MAX_DOMAIN_NAME_LEN + 4];
|
||||
PIP_ADDR_STRING CurrentDnsServer;
|
||||
IP_ADDR_STRING DnsServerList;
|
||||
UINT NodeType;
|
||||
char ScopeId[MAX_SCOPE_ID_LEN + 4];
|
||||
UINT EnableRouting;
|
||||
UINT EnableProxy;
|
||||
UINT EnableDns;
|
||||
} FIXED_INFO, *PFIXED_INFO;
|
||||
#endif
|
||||
|
||||
typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PULONG);
|
||||
|
||||
static jdns_string_t *reg_readString(HKEY hk, const char *subkey)
|
||||
{
|
||||
char *buf;
|
||||
DWORD bufsize;
|
||||
int ret;
|
||||
jdns_string_t *str = 0;
|
||||
|
||||
bufsize = 1024;
|
||||
buf = (char *)jdns_alloc((int)bufsize);
|
||||
if(!buf)
|
||||
return 0;
|
||||
ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
|
||||
if(ret == ERROR_MORE_DATA)
|
||||
{
|
||||
buf = (char *)jdns_realloc(buf, bufsize);
|
||||
if(!buf)
|
||||
{
|
||||
jdns_free(buf);
|
||||
return 0;
|
||||
}
|
||||
ret = RegQueryValueExA(hk, subkey, 0, 0, (LPBYTE)buf, &bufsize);
|
||||
}
|
||||
if(ret == ERROR_SUCCESS)
|
||||
{
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, (char *)buf);
|
||||
}
|
||||
jdns_free(buf);
|
||||
return str;
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_winreg()
|
||||
{
|
||||
int n;
|
||||
jdns_dnsparams_t *params;
|
||||
HKEY key;
|
||||
int ret;
|
||||
char sep;
|
||||
jdns_string_t *str_domain, *str_nameserver, *str_searchlist;
|
||||
jdns_stringlist_t *list_nameserver, *list_searchlist;
|
||||
|
||||
sep = ' ';
|
||||
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"System\\CurrentControlSet\\Services\\Tcpip\\Parameters",
|
||||
0, KEY_READ, &key);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
{
|
||||
sep = ',';
|
||||
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||
"System\\CurrentControlSet\\Services\\VxD\\MSTCP",
|
||||
0, KEY_READ, &key);
|
||||
if(ret != ERROR_SUCCESS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
str_domain = reg_readString(key, "DhcpDomain");
|
||||
if(!str_domain)
|
||||
str_domain = reg_readString(key, "Domain");
|
||||
str_nameserver = reg_readString(key, "DhcpNameServer");
|
||||
if(!str_nameserver)
|
||||
str_nameserver = reg_readString(key, "NameServer");
|
||||
str_searchlist = reg_readString(key, "SearchList");
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
list_nameserver = 0;
|
||||
if(str_nameserver)
|
||||
{
|
||||
list_nameserver = string_split(str_nameserver, sep);
|
||||
jdns_string_delete(str_nameserver);
|
||||
}
|
||||
list_searchlist = 0;
|
||||
if(str_searchlist)
|
||||
{
|
||||
// lowercase the string
|
||||
jdns_string_t *p = string_tolower(str_searchlist);
|
||||
jdns_string_delete(str_searchlist);
|
||||
str_searchlist = p;
|
||||
|
||||
list_searchlist = string_split(str_searchlist, sep);
|
||||
jdns_string_delete(str_searchlist);
|
||||
}
|
||||
|
||||
params = jdns_dnsparams_new();
|
||||
if(list_nameserver)
|
||||
{
|
||||
// qt seems to do a strange thing here by running each name
|
||||
// server address through the q3dns setLabel function, and
|
||||
// then pulls the result as a list of addresses. i have
|
||||
// no idea why they do this, or how one IP address would
|
||||
// turn into anything else, let alone several addresses.
|
||||
// so, uh, we're not going to do that.
|
||||
for(n = 0; n < list_nameserver->count; ++n)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
if(jdns_address_set_cstr(addr, (char *)list_nameserver->item[n]->data))
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
jdns_stringlist_delete(list_nameserver);
|
||||
}
|
||||
if(str_domain)
|
||||
{
|
||||
if(str_domain->size > 0)
|
||||
jdns_dnsparams_append_domain(params, str_domain);
|
||||
jdns_string_delete(str_domain);
|
||||
}
|
||||
if(list_searchlist)
|
||||
{
|
||||
for(n = 0; n < list_searchlist->count; ++n)
|
||||
{
|
||||
if(list_searchlist->item[n]->size > 0)
|
||||
jdns_dnsparams_append_domain(params, list_searchlist->item[n]);
|
||||
}
|
||||
jdns_stringlist_delete(list_searchlist);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_winsys()
|
||||
{
|
||||
jdns_dnsparams_t *params;
|
||||
GetNetworkParamsFunc myGetNetworkParams;
|
||||
DWORD ret;
|
||||
HINSTANCE lib;
|
||||
jdns_address_t *addr;
|
||||
jdns_string_t *str;
|
||||
IP_ADDR_STRING *ipstr;
|
||||
|
||||
lib = LoadLibraryA("iphlpapi");
|
||||
if(!lib)
|
||||
return 0;
|
||||
|
||||
params = 0;
|
||||
myGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(lib, "GetNetworkParams");
|
||||
if(myGetNetworkParams)
|
||||
{
|
||||
ULONG bufsize = 0;
|
||||
ret = myGetNetworkParams(0, &bufsize);
|
||||
if(ret == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
FIXED_INFO *info = (FIXED_INFO *)jdns_alloc((int)bufsize);
|
||||
ret = myGetNetworkParams(info, &bufsize);
|
||||
if(ret == ERROR_SUCCESS)
|
||||
{
|
||||
params = jdns_dnsparams_new();
|
||||
ipstr = &info->DnsServerList;
|
||||
while(ipstr)
|
||||
{
|
||||
addr = jdns_address_new();
|
||||
if(jdns_address_set_cstr(addr, (char *)ipstr->IpAddress.String))
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
ipstr = ipstr->Next;
|
||||
}
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, info->DomainName);
|
||||
if(str->size > 0)
|
||||
jdns_dnsparams_append_domain(params, str);
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
jdns_free(info);
|
||||
}
|
||||
}
|
||||
FreeLibrary(lib);
|
||||
return params;
|
||||
}
|
||||
|
||||
static void apply_win_hosts_file(jdns_dnsparams_t *a)
|
||||
{
|
||||
char *p, *str;
|
||||
int len;
|
||||
|
||||
p = getenv("WINDIR");
|
||||
if(!p)
|
||||
return;
|
||||
len = strlen(p);
|
||||
str = (char *)jdns_alloc(len + 100); // should be enough
|
||||
memcpy(str, p, len);
|
||||
strcpy(str + len, "\\system32\\drivers\\etc\\hosts"); // winnt+
|
||||
apply_hosts_file(a, str);
|
||||
strcpy(str + len, "\\hosts"); // win9x
|
||||
apply_hosts_file(a, str);
|
||||
jdns_free(str);
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_win()
|
||||
{
|
||||
int n;
|
||||
jdns_dnsparams_t *sys_params, *reg_params;
|
||||
|
||||
reg_params = dnsparams_get_winreg();
|
||||
sys_params = dnsparams_get_winsys();
|
||||
|
||||
// no sys params? take the reg params then
|
||||
if(!sys_params)
|
||||
{
|
||||
apply_win_hosts_file(reg_params);
|
||||
return reg_params;
|
||||
}
|
||||
|
||||
// sys params don't have a search list, so merge the domains from
|
||||
// the registry if possible
|
||||
if(reg_params)
|
||||
{
|
||||
for(n = 0; n < reg_params->domains->count; ++n)
|
||||
{
|
||||
jdns_string_t *reg_str = reg_params->domains->item[n];
|
||||
|
||||
// don't add dups
|
||||
if(!dnsparams_have_domain(sys_params, reg_str))
|
||||
jdns_dnsparams_append_domain(sys_params, reg_str);
|
||||
}
|
||||
jdns_dnsparams_delete(reg_params);
|
||||
}
|
||||
apply_win_hosts_file(sys_params);
|
||||
return sys_params;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JDNS_OS_UNIX
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_unixfiles()
|
||||
{
|
||||
FILE *f;
|
||||
int n;
|
||||
jdns_dnsparams_t *params;
|
||||
jdns_string_t *line, *simp;
|
||||
jdns_stringlist_t *parts;
|
||||
|
||||
params = jdns_dnsparams_new();
|
||||
|
||||
f = fopen("/etc/resolv.conf", "r");
|
||||
if(!f)
|
||||
return params;
|
||||
while(1)
|
||||
{
|
||||
line = file_nextline(f);
|
||||
if(!line)
|
||||
break;
|
||||
|
||||
// truncate at comment
|
||||
n = string_indexOf(line, '#', 0);
|
||||
if(n != -1)
|
||||
{
|
||||
line->size = n;
|
||||
line->data[n] = 0;
|
||||
}
|
||||
|
||||
simp = string_simplify(line);
|
||||
jdns_string_delete(line);
|
||||
|
||||
parts = string_split(simp, ' ');
|
||||
jdns_string_delete(simp);
|
||||
|
||||
if(parts->count < 2)
|
||||
{
|
||||
jdns_stringlist_delete(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
simp = string_tolower(parts->item[0]);
|
||||
if(strcmp((char *)simp->data, "nameserver") == 0)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
jdns_address_set_cstr(addr, (const char *)parts->item[1]->data);
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
else if(strcmp((char *)simp->data, "search") == 0)
|
||||
{
|
||||
for(n = 1; n < parts->count; ++n)
|
||||
{
|
||||
jdns_dnsparams_append_domain(params, parts->item[n]);
|
||||
}
|
||||
}
|
||||
else if(strcmp((char *)simp->data, "domain") == 0)
|
||||
{
|
||||
jdns_dnsparams_append_domain(params, parts->item[1]);
|
||||
}
|
||||
jdns_string_delete(simp);
|
||||
|
||||
jdns_stringlist_delete(parts);
|
||||
}
|
||||
fclose(f);
|
||||
return params;
|
||||
}
|
||||
|
||||
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
|
||||
# define JDNS_MODERN_RES_API
|
||||
#endif
|
||||
|
||||
#ifndef JDNS_MODERN_RES_API
|
||||
typedef int (*res_init_func)();
|
||||
static int my_res_init()
|
||||
{
|
||||
#ifdef JDNS_OS_MAC
|
||||
res_init_func mac_res_init;
|
||||
|
||||
// look up res_init in the system library (qt does this, not sure why)
|
||||
mac_res_init = (res_init_func)dlsym(RTLD_NEXT, "res_init");
|
||||
if(!mac_res_init)
|
||||
return -1;
|
||||
return mac_res_init();
|
||||
#else
|
||||
return res_init();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __res_state_ext
|
||||
# define USE_EXTEXT
|
||||
#endif
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_unixsys()
|
||||
{
|
||||
int n;
|
||||
jdns_dnsparams_t *params;
|
||||
|
||||
#ifdef JDNS_MODERN_RES_API
|
||||
struct __res_state res;
|
||||
memset(&res, 0, sizeof(struct __res_state));
|
||||
n = res_ninit(&res);
|
||||
#define RESVAR res
|
||||
#else
|
||||
n = my_res_init();
|
||||
#define RESVAR _res
|
||||
#endif
|
||||
|
||||
params = jdns_dnsparams_new();
|
||||
|
||||
// error initializing?
|
||||
if(n == -1)
|
||||
return params;
|
||||
|
||||
// nameservers - ipv6
|
||||
for(n = 0; n < MAXNS && n < RESVAR._u._ext.nscount; ++n)
|
||||
{
|
||||
jdns_address_t *addr;
|
||||
struct sockaddr_in6 *sa6;
|
||||
|
||||
#ifdef USE_EXTEXT
|
||||
sa6 = ((struct sockaddr_in6 *)RESVAR._u._ext.ext) + n;
|
||||
#else
|
||||
sa6 = RESVAR._u._ext.nsaddrs[n];
|
||||
#endif
|
||||
|
||||
if(sa6 == NULL)
|
||||
continue;
|
||||
addr = jdns_address_new();
|
||||
jdns_address_set_ipv6(addr, sa6->sin6_addr.s6_addr);
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
|
||||
// nameservers - ipv4
|
||||
for(n = 0; n < MAXNS && n < RESVAR.nscount; ++n)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
jdns_address_set_ipv4(addr, ntohl(RESVAR.nsaddr_list[n].sin_addr.s_addr));
|
||||
jdns_dnsparams_append_nameserver(params, addr, JDNS_UNICAST_PORT);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
|
||||
// domain name
|
||||
if(strlen(RESVAR.defdname) > 0)
|
||||
{
|
||||
jdns_string_t *str;
|
||||
jdns_string_t *p;
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, RESVAR.defdname);
|
||||
p = string_tolower(str);
|
||||
jdns_string_delete(str);
|
||||
str = p;
|
||||
jdns_dnsparams_append_domain(params, str);
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
|
||||
// search list
|
||||
#ifdef MAXDFLSRCH
|
||||
for(n = 0; n < MAXDFLSRCH && RESVAR.dnsrch[n]; ++n)
|
||||
{
|
||||
if(strlen(RESVAR.dnsrch[n]) > 0)
|
||||
{
|
||||
jdns_string_t *str;
|
||||
jdns_string_t *p;
|
||||
str = jdns_string_new();
|
||||
jdns_string_set_cstr(str, RESVAR.dnsrch[n]);
|
||||
p = string_tolower(str);
|
||||
jdns_string_delete(str);
|
||||
str = p;
|
||||
|
||||
// don't add dups
|
||||
if(!dnsparams_have_domain(params, str))
|
||||
jdns_dnsparams_append_domain(params, str);
|
||||
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static jdns_dnsparams_t *dnsparams_get_unix()
|
||||
{
|
||||
jdns_dnsparams_t *params;
|
||||
|
||||
// prefer system calls over files
|
||||
params = dnsparams_get_unixsys();
|
||||
if(params->nameservers->count == 0)
|
||||
{
|
||||
jdns_dnsparams_delete(params);
|
||||
params = dnsparams_get_unixfiles();
|
||||
}
|
||||
|
||||
apply_hosts_file(params, "/etc/hosts");
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
jdns_dnsparams_t *jdns_system_dnsparams()
|
||||
{
|
||||
#ifdef JDNS_OS_WIN
|
||||
return dnsparams_get_win();
|
||||
#else
|
||||
return dnsparams_get_unix();
|
||||
#endif
|
||||
}
|
||||
1471
iris-legacy/iris/irisnet/jdns/jdns_util.c
Normal file
1471
iris-legacy/iris/irisnet/jdns/jdns_util.c
Normal file
File diff suppressed because it is too large
Load diff
596
iris-legacy/iris/irisnet/jdns/main.cpp
Normal file
596
iris-legacy/iris/irisnet/jdns/main.cpp
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
/*
|
||||
* Copyright (C) 2005 Justin Karneges
|
||||
*
|
||||
* 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 <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include "qjdns.h"
|
||||
|
||||
QString dataToString(const QByteArray &buf)
|
||||
{
|
||||
QString out;
|
||||
for(int n = 0; n < buf.size(); ++n)
|
||||
{
|
||||
unsigned char c = (unsigned char)buf[n];
|
||||
if(c == '\\')
|
||||
out += "\\\\";
|
||||
else if(c >= 0x20 && c < 0x7f)
|
||||
out += c;
|
||||
else
|
||||
out += QString().sprintf("\\x%02x", (unsigned int)c);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void print_record(const QJDns::Record &r)
|
||||
{
|
||||
switch(r.type)
|
||||
{
|
||||
case QJDns::A:
|
||||
printf(" A: [%s] (ttl=%d)\n", qPrintable(r.address.toString()), r.ttl);
|
||||
break;
|
||||
case QJDns::Aaaa:
|
||||
printf(" AAAA: [%s] (ttl=%d)\n", qPrintable(r.address.toString()), r.ttl);
|
||||
break;
|
||||
case QJDns::Mx:
|
||||
printf(" MX: [%s] priority=%d (ttl=%d)\n", r.name.data(), r.priority, r.ttl);
|
||||
break;
|
||||
case QJDns::Srv:
|
||||
printf(" SRV: [%s] port=%d priority=%d weight=%d (ttl=%d)\n", r.name.data(), r.port, r.priority, r.weight, r.ttl);
|
||||
break;
|
||||
case QJDns::Cname:
|
||||
printf(" CNAME: [%s] (ttl=%d)\n", r.name.data(), r.ttl);
|
||||
break;
|
||||
case QJDns::Ptr:
|
||||
printf(" PTR: [%s] (ttl=%d)\n", r.name.data(), r.ttl);
|
||||
break;
|
||||
case QJDns::Txt:
|
||||
{
|
||||
printf(" TXT: count=%d (ttl=%d)\n", r.texts.count(), r.ttl);
|
||||
for(int n = 0; n < r.texts.count(); ++n)
|
||||
printf(" len=%d [%s]\n", r.texts[n].size(), qPrintable(dataToString(r.texts[n])));
|
||||
break;
|
||||
}
|
||||
case QJDns::Hinfo:
|
||||
printf(" HINFO: [%s] [%s] (ttl=%d)\n", r.cpu.data(), r.os.data(), r.ttl);
|
||||
break;
|
||||
case QJDns::Ns:
|
||||
printf(" NS: [%s] (ttl=%d)\n", r.name.data(), r.ttl);
|
||||
break;
|
||||
default:
|
||||
printf(" (Unknown): type=%d, size=%d (ttl=%d)\n", r.type, r.rdata.size(), r.ttl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class App : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
bool opt_debug, opt_ipv6, opt_quit;
|
||||
int quit_time;
|
||||
QString mode, type, name, ipaddr;
|
||||
QStringList nslist;
|
||||
QList<QJDns::Record> pubitems;
|
||||
QJDns jdns;
|
||||
int req_id;
|
||||
|
||||
App()
|
||||
{
|
||||
connect(&jdns, SIGNAL(resultsReady(int, const QJDns::Response &)), SLOT(jdns_resultsReady(int, const QJDns::Response &)));
|
||||
connect(&jdns, SIGNAL(published(int)), SLOT(jdns_published(int)));
|
||||
connect(&jdns, SIGNAL(error(int, QJDns::Error)), SLOT(jdns_error(int, QJDns::Error)));
|
||||
connect(&jdns, SIGNAL(shutdownFinished()), SLOT(jdns_shutdownFinished()));
|
||||
connect(&jdns, SIGNAL(debugLinesReady()), SLOT(jdns_debugLinesReady()));
|
||||
}
|
||||
|
||||
~App()
|
||||
{
|
||||
}
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
if(mode == "uni")
|
||||
{
|
||||
if(!jdns.init(QJDns::Unicast, opt_ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any))
|
||||
{
|
||||
jdns_debugLinesReady();
|
||||
printf("unable to bind\n");
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QJDns::NameServer> addrs;
|
||||
for(int n = 0; n < nslist.count(); ++n)
|
||||
{
|
||||
QJDns::NameServer host;
|
||||
QString str = nslist[n];
|
||||
if(str == "mul")
|
||||
{
|
||||
if(opt_ipv6)
|
||||
host.address = QHostAddress("FF02::FB");
|
||||
else
|
||||
host.address = QHostAddress("224.0.0.251");
|
||||
host.port = 5353;
|
||||
}
|
||||
else
|
||||
{
|
||||
int at = str.indexOf(';');
|
||||
if(at != -1)
|
||||
{
|
||||
host.address = QHostAddress(str.mid(0, at));
|
||||
host.port = str.mid(at + 1).toInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
host.address = QHostAddress(str);
|
||||
}
|
||||
}
|
||||
|
||||
if(host.address.isNull() || host.port <= 0)
|
||||
{
|
||||
printf("bad nameserver: [%s]\n", qPrintable(nslist[n]));
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
addrs += host;
|
||||
}
|
||||
|
||||
if(addrs.isEmpty())
|
||||
addrs = QJDns::systemInfo().nameServers;
|
||||
|
||||
if(addrs.isEmpty())
|
||||
{
|
||||
printf("no nameservers were detected or specified\n");
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
|
||||
jdns.setNameServers(addrs);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!jdns.init(QJDns::Multicast, opt_ipv6 ? QHostAddress::AnyIPv6 : QHostAddress::Any))
|
||||
{
|
||||
jdns_debugLinesReady();
|
||||
printf("unable to bind\n");
|
||||
emit quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == "uni" || mode == "mul")
|
||||
{
|
||||
int x = QJDns::A;
|
||||
if(type == "ptr")
|
||||
x = QJDns::Ptr;
|
||||
else if(type == "srv")
|
||||
x = QJDns::Srv;
|
||||
else if(type == "a")
|
||||
x = QJDns::A;
|
||||
else if(type == "aaaa")
|
||||
x = QJDns::Aaaa;
|
||||
else if(type == "mx")
|
||||
x = QJDns::Mx;
|
||||
else if(type == "txt")
|
||||
x = QJDns::Txt;
|
||||
else if(type == "hinfo")
|
||||
x = QJDns::Hinfo;
|
||||
else if(type == "cname")
|
||||
x = QJDns::Cname;
|
||||
else if(type == "any")
|
||||
x = QJDns::Any;
|
||||
else
|
||||
{
|
||||
bool ok;
|
||||
int y = type.toInt(&ok);
|
||||
if(ok)
|
||||
x = y;
|
||||
}
|
||||
|
||||
req_id = jdns.queryStart(name.toLatin1(), x);
|
||||
printf("[%d] Querying for [%s] type=%d ...\n", req_id, qPrintable(name), x);
|
||||
}
|
||||
else // publish
|
||||
{
|
||||
for(int n = 0; n < pubitems.count(); ++n)
|
||||
{
|
||||
const QJDns::Record &rr = pubitems[n];
|
||||
QJDns::PublishMode m = QJDns::Unique;
|
||||
if(rr.type == QJDns::Ptr)
|
||||
m = QJDns::Shared;
|
||||
int id = jdns.publishStart(m, rr);
|
||||
printf("[%d] Publishing [%s] type=%d ...\n", id, rr.owner.data(), rr.type);
|
||||
}
|
||||
}
|
||||
|
||||
if(opt_quit)
|
||||
QTimer::singleShot(quit_time * 1000, this, SLOT(doShutdown()));
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void jdns_resultsReady(int id, const QJDns::Response &results)
|
||||
{
|
||||
printf("[%d] Results\n", id);
|
||||
for(int n = 0; n < results.answerRecords.count(); ++n)
|
||||
print_record(results.answerRecords[n]);
|
||||
|
||||
if(mode == "uni")
|
||||
jdns.shutdown();
|
||||
}
|
||||
|
||||
void jdns_published(int id)
|
||||
{
|
||||
printf("[%d] Published\n", id);
|
||||
}
|
||||
|
||||
void jdns_error(int id, QJDns::Error e)
|
||||
{
|
||||
QString str;
|
||||
if(e == QJDns::ErrorGeneric)
|
||||
str = "Generic";
|
||||
else if(e == QJDns::ErrorNXDomain)
|
||||
str = "NXDomain";
|
||||
else if(e == QJDns::ErrorTimeout)
|
||||
str = "Timeout";
|
||||
else if(e == QJDns::ErrorConflict)
|
||||
str = "Conflict";
|
||||
printf("[%d] Error: %s\n", id, qPrintable(str));
|
||||
jdns.shutdown();
|
||||
}
|
||||
|
||||
void jdns_shutdownFinished()
|
||||
{
|
||||
emit quit();
|
||||
}
|
||||
|
||||
void jdns_debugLinesReady()
|
||||
{
|
||||
QStringList lines = jdns.debugLines();
|
||||
if(opt_debug)
|
||||
{
|
||||
for(int n = 0; n < lines.count(); ++n)
|
||||
printf("jdns: %s\n", qPrintable(lines[n]));
|
||||
}
|
||||
}
|
||||
|
||||
void doShutdown()
|
||||
{
|
||||
jdns.shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
#include "main.moc"
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("usage: jdns (options) uni [type] [name] (nameserver(;port)|mul ...)\n");
|
||||
printf(" jdns (options) mul [type] [name]\n");
|
||||
printf(" jdns (options) pub [items ...]\n");
|
||||
printf(" jdns sys\n");
|
||||
printf("\n");
|
||||
printf("options:\n");
|
||||
printf(" -d show debug output\n");
|
||||
printf(" -6 use ipv6\n");
|
||||
printf(" -q x quit x seconds after starting\n");
|
||||
printf("\n");
|
||||
printf("uni/mul types: a aaaa ptr srv mx txt hinfo cname any\n");
|
||||
printf("pub items: ptr:name,answer srv:name,answer,port a:name,ipaddr\n");
|
||||
printf(" txt:name,str0,...,strn aaaa:name,ipaddr\n");
|
||||
printf("\n");
|
||||
printf("examples:\n");
|
||||
printf(" jdns uni a jabber.org 192.168.0.1\n");
|
||||
printf(" jdns uni srv _xmpp-client._tcp.jabber.org 192.168.0.1;53\n");
|
||||
printf(" jdns uni 10 user@host._presence._tcp.local mul\n");
|
||||
printf(" jdns mul a foobar.local\n");
|
||||
printf(" jdns mul ptr _services._dns-sd._udp.local\n");
|
||||
printf(" jdns pub a:mybox.local.,192.168.0.55\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get args
|
||||
QStringList args;
|
||||
for(int n = 1; n < argc; ++n)
|
||||
args += QString(argv[n]);
|
||||
|
||||
bool opt_debug = false;
|
||||
bool opt_ipv6 = false;
|
||||
bool opt_quit = false;
|
||||
int quit_time = 0;
|
||||
QString mode, type, name, ipaddr;
|
||||
QStringList nslist;
|
||||
QList<QJDns::Record> pubitems;
|
||||
|
||||
// options
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
{
|
||||
if(args[n].left(1) == "-")
|
||||
{
|
||||
if(args[n] == "-d")
|
||||
opt_debug = true;
|
||||
else if(args[n] == "-6")
|
||||
opt_ipv6 = true;
|
||||
else if(args[n] == "-q")
|
||||
{
|
||||
if(n + 1 >= args.count())
|
||||
{
|
||||
printf("need to specify number of seconds\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int x = args[n + 1].toInt();
|
||||
if(x < 1)
|
||||
x = 30;
|
||||
|
||||
opt_quit = true;
|
||||
quit_time = x;
|
||||
|
||||
args.removeAt(n + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("bad option\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
args.removeAt(n);
|
||||
--n; // adjust position
|
||||
}
|
||||
}
|
||||
|
||||
mode = args[0];
|
||||
if(mode == "uni" || mode == "mul")
|
||||
{
|
||||
if(args.count() < 3)
|
||||
{
|
||||
printf("not enough args\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
type = args[1];
|
||||
name = args[2];
|
||||
if(mode == "uni")
|
||||
{
|
||||
for(int n = 3; n < args.count(); ++n)
|
||||
nslist += QString(args[n]);
|
||||
}
|
||||
}
|
||||
else if(mode == "pub")
|
||||
{
|
||||
if(args.count() < 2)
|
||||
{
|
||||
printf("not enough args\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
for(int n = 1; n < args.count(); ++n)
|
||||
{
|
||||
QString arg = args[n];
|
||||
int at = arg.indexOf(':');
|
||||
if(at == -1)
|
||||
{
|
||||
printf("missing colon\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
QString type = arg.mid(0, at).toLower();
|
||||
QString val = arg.mid(at + 1);
|
||||
if(type == "a")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 2)
|
||||
{
|
||||
printf("bad format for A type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
QHostAddress host(list[1]);
|
||||
if(host.isNull() || host.protocol() != QAbstractSocket::IPv4Protocol)
|
||||
{
|
||||
printf("bad format for A type IP address\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::A;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = host;
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "aaaa")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 2)
|
||||
{
|
||||
printf("bad format for AAAA type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
QHostAddress host(list[1]);
|
||||
if(host.isNull() || host.protocol() != QAbstractSocket::IPv6Protocol)
|
||||
{
|
||||
printf("bad format for AAAA type IP address\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Aaaa;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = host;
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "srv")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 3)
|
||||
{
|
||||
printf("bad format for SRV type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Srv;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.name = list[1].toLatin1();
|
||||
rec.priority = 0;
|
||||
rec.weight = 0;
|
||||
rec.port = list[2].toInt();
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "ptr")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
if(list.count() != 2)
|
||||
{
|
||||
printf("bad format for PTR type\n");
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Ptr;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.name = list[1].toLatin1();
|
||||
pubitems += rec;
|
||||
}
|
||||
else if(type == "txt")
|
||||
{
|
||||
QStringList list = val.split(',');
|
||||
QList<QByteArray> texts;
|
||||
for(int n = 1; n < list.count(); ++n)
|
||||
texts += list[n].toLatin1();
|
||||
|
||||
QJDns::Record rec;
|
||||
rec.owner = list[0].toLatin1();
|
||||
rec.type = QJDns::Txt;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.texts = texts;
|
||||
pubitems += rec;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("bad record type [%s]\n", qPrintable(type));
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(mode == "sys")
|
||||
{
|
||||
QJDns::SystemInfo info = QJDns::systemInfo();
|
||||
|
||||
printf("DNS System Information\n");
|
||||
printf(" Name Servers:\n");
|
||||
if(!info.nameServers.isEmpty())
|
||||
{
|
||||
for(int n = 0; n < info.nameServers.count(); ++n)
|
||||
printf(" %s\n", qPrintable(info.nameServers[n].address.toString()));
|
||||
}
|
||||
else
|
||||
printf(" (None)\n");
|
||||
|
||||
printf(" Domains:\n");
|
||||
if(!info.domains.isEmpty())
|
||||
{
|
||||
for(int n = 0; n < info.domains.count(); ++n)
|
||||
printf(" [%s]\n", info.domains[n].data());
|
||||
}
|
||||
else
|
||||
printf(" (None)\n");
|
||||
|
||||
printf(" Hosts:\n");
|
||||
if(!info.hosts.isEmpty())
|
||||
{
|
||||
for(int n = 0; n < info.hosts.count(); ++n)
|
||||
{
|
||||
const QJDns::DnsHost &h = info.hosts[n];
|
||||
printf(" [%s] -> %s\n", h.name.data(), qPrintable(h.address.toString()));
|
||||
}
|
||||
}
|
||||
else
|
||||
printf(" (None)\n");
|
||||
|
||||
QHostAddress addr;
|
||||
printf("Primary IPv4 Multicast Address: ");
|
||||
addr = QJDns::detectPrimaryMulticast(QHostAddress::Any);
|
||||
if(!addr.isNull())
|
||||
printf("%s\n", qPrintable(addr.toString()));
|
||||
else
|
||||
printf("(None)\n");
|
||||
printf("Primary IPv6 Multicast Address: ");
|
||||
addr = QJDns::detectPrimaryMulticast(QHostAddress::AnyIPv6);
|
||||
if(!addr.isNull())
|
||||
printf("%s\n", qPrintable(addr.toString()));
|
||||
else
|
||||
printf("(None)\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
App a;
|
||||
a.opt_debug = opt_debug;
|
||||
a.opt_ipv6 = opt_ipv6;
|
||||
a.opt_quit = opt_quit;
|
||||
a.quit_time = quit_time;
|
||||
a.mode = mode;
|
||||
a.type = type.toLower();
|
||||
a.name = name;
|
||||
a.ipaddr = ipaddr;
|
||||
a.nslist = nslist;
|
||||
a.pubitems = pubitems;
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
return 0;
|
||||
}
|
||||
908
iris-legacy/iris/irisnet/jdns/qjdns.cpp
Normal file
908
iris-legacy/iris/irisnet/jdns/qjdns.cpp
Normal file
|
|
@ -0,0 +1,908 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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 "qjdns.h"
|
||||
|
||||
#include <time.h>
|
||||
#include "qjdns_sock.h"
|
||||
#include "jdns.h"
|
||||
|
||||
static jdns_string_t *qt2str(const QByteArray &in)
|
||||
{
|
||||
jdns_string_t *out = jdns_string_new();
|
||||
jdns_string_set(out, (const unsigned char *)in.data(), in.size());
|
||||
return out;
|
||||
}
|
||||
|
||||
static QByteArray str2qt(const jdns_string_t *in)
|
||||
{
|
||||
return QByteArray((const char *)in->data, in->size);
|
||||
}
|
||||
|
||||
static void qt2addr_set(jdns_address_t *addr, const QHostAddress &host)
|
||||
{
|
||||
if(host.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
jdns_address_set_ipv6(addr, host.toIPv6Address().c);
|
||||
else
|
||||
jdns_address_set_ipv4(addr, host.toIPv4Address());
|
||||
}
|
||||
|
||||
static jdns_address_t *qt2addr(const QHostAddress &host)
|
||||
{
|
||||
jdns_address_t *addr = jdns_address_new();
|
||||
qt2addr_set(addr, host);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static QHostAddress addr2qt(const jdns_address_t *addr)
|
||||
{
|
||||
if(addr->isIpv6)
|
||||
return QHostAddress(addr->addr.v6);
|
||||
else
|
||||
return QHostAddress(addr->addr.v4);
|
||||
}
|
||||
|
||||
static QJDns::Record import_record(const jdns_rr_t *in)
|
||||
{
|
||||
QJDns::Record out;
|
||||
|
||||
out.owner = QByteArray((const char *)in->owner);
|
||||
out.ttl = in->ttl;
|
||||
out.type = in->type;
|
||||
out.rdata = QByteArray((const char *)in->rdata, in->rdlength);
|
||||
|
||||
// known
|
||||
if(in->haveKnown)
|
||||
{
|
||||
int type = in->type;
|
||||
|
||||
if(type == QJDns::A || type == QJDns::Aaaa)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.address = addr2qt(in->data.address);
|
||||
}
|
||||
else if(type == QJDns::Mx)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.name = QByteArray((const char *)in->data.server->name);
|
||||
out.priority = in->data.server->priority;
|
||||
}
|
||||
else if(type == QJDns::Srv)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.name = QByteArray((const char *)in->data.server->name);
|
||||
out.priority = in->data.server->priority;
|
||||
out.weight = in->data.server->weight;
|
||||
out.port = in->data.server->port;
|
||||
}
|
||||
else if(type == QJDns::Cname || type == QJDns::Ptr || type == QJDns::Ns)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.name = QByteArray((const char *)in->data.name);
|
||||
}
|
||||
else if(type == QJDns::Txt)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.texts.clear();
|
||||
for(int n = 0; n < in->data.texts->count; ++n)
|
||||
out.texts += str2qt(in->data.texts->item[n]);
|
||||
}
|
||||
else if(type == QJDns::Hinfo)
|
||||
{
|
||||
out.haveKnown = true;
|
||||
out.cpu = str2qt(in->data.hinfo.cpu);
|
||||
out.os = str2qt(in->data.hinfo.os);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static jdns_rr_t *export_record(const QJDns::Record &in)
|
||||
{
|
||||
jdns_rr_t *out = jdns_rr_new();
|
||||
|
||||
jdns_rr_set_owner(out, (const unsigned char *)in.owner.data());
|
||||
out->ttl = in.ttl;
|
||||
|
||||
// if we have known, use that
|
||||
if(in.haveKnown)
|
||||
{
|
||||
int type = in.type;
|
||||
|
||||
if(type == QJDns::A)
|
||||
{
|
||||
jdns_address_t *addr = qt2addr(in.address);
|
||||
jdns_rr_set_A(out, addr);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
else if(type == QJDns::Aaaa)
|
||||
{
|
||||
jdns_address_t *addr = qt2addr(in.address);
|
||||
jdns_rr_set_AAAA(out, addr);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
else if(type == QJDns::Mx)
|
||||
{
|
||||
jdns_rr_set_MX(out, (const unsigned char *)in.name.data(), in.priority);
|
||||
}
|
||||
else if(type == QJDns::Srv)
|
||||
{
|
||||
jdns_rr_set_SRV(out, (const unsigned char *)in.name.data(), in.port, in.priority, in.weight);
|
||||
}
|
||||
else if(type == QJDns::Cname)
|
||||
{
|
||||
jdns_rr_set_CNAME(out, (const unsigned char *)in.name.data());
|
||||
}
|
||||
else if(type == QJDns::Ptr)
|
||||
{
|
||||
jdns_rr_set_PTR(out, (const unsigned char *)in.name.data());
|
||||
}
|
||||
else if(type == QJDns::Txt)
|
||||
{
|
||||
jdns_stringlist_t *list = jdns_stringlist_new();
|
||||
for(int n = 0; n < in.texts.count(); ++n)
|
||||
{
|
||||
jdns_string_t *str = qt2str(in.texts[n]);
|
||||
jdns_stringlist_append(list, str);
|
||||
jdns_string_delete(str);
|
||||
}
|
||||
jdns_rr_set_TXT(out, list);
|
||||
jdns_stringlist_delete(list);
|
||||
}
|
||||
else if(type == QJDns::Hinfo)
|
||||
{
|
||||
jdns_string_t *cpu = qt2str(in.cpu);
|
||||
jdns_string_t *os = qt2str(in.os);
|
||||
jdns_rr_set_HINFO(out, cpu, os);
|
||||
jdns_string_delete(cpu);
|
||||
jdns_string_delete(os);
|
||||
}
|
||||
else if(type == QJDns::Ns)
|
||||
{
|
||||
jdns_rr_set_NS(out, (const unsigned char *)in.name.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
jdns_rr_set_record(out, in.type, (const unsigned char *)in.rdata.data(), in.rdata.size());
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QJDns::NameServer
|
||||
//----------------------------------------------------------------------------
|
||||
QJDns::NameServer::NameServer()
|
||||
{
|
||||
port = JDNS_UNICAST_PORT;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QJDns::Record
|
||||
//----------------------------------------------------------------------------
|
||||
QJDns::Record::Record()
|
||||
{
|
||||
ttl = 0;
|
||||
type = -1;
|
||||
haveKnown = false;
|
||||
}
|
||||
|
||||
bool QJDns::Record::verify() const
|
||||
{
|
||||
jdns_rr_t *rr = export_record(*this);
|
||||
int ok = jdns_rr_verify(rr);
|
||||
jdns_rr_delete(rr);
|
||||
return (ok ? true : false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// QJDns
|
||||
//----------------------------------------------------------------------------
|
||||
static int my_srand_done = 0;
|
||||
|
||||
static void my_srand()
|
||||
{
|
||||
if(my_srand_done)
|
||||
return;
|
||||
|
||||
// lame attempt at randomizing without srand
|
||||
int count = ::time(NULL) % 128;
|
||||
for(int n = 0; n < count; ++n)
|
||||
rand();
|
||||
|
||||
my_srand_done = 1;
|
||||
}
|
||||
|
||||
class QJDns::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class LateError
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
Error error;
|
||||
};
|
||||
|
||||
class LateResponse
|
||||
{
|
||||
public:
|
||||
int id;
|
||||
QJDns::Response response;
|
||||
};
|
||||
|
||||
QJDns *q;
|
||||
QJDns::Mode mode;
|
||||
jdns_session_t *sess;
|
||||
bool shutting_down;
|
||||
QTimer stepTrigger, debugTrigger;
|
||||
QTimer stepTimeout;
|
||||
QTime clock;
|
||||
QStringList debug_strings;
|
||||
bool new_debug_strings;
|
||||
int next_handle;
|
||||
bool need_handle;
|
||||
QHash<int,QUdpSocket*> socketForHandle;
|
||||
QHash<QUdpSocket*,int> handleForSocket;
|
||||
int pending;
|
||||
bool pending_wait;
|
||||
bool complete_shutdown;
|
||||
QList<LateError> lateErrors;
|
||||
|
||||
Private(QJDns *_q) : QObject(_q), q(_q), stepTrigger(this), debugTrigger(this), stepTimeout(this)
|
||||
{
|
||||
sess = 0;
|
||||
shutting_down = false;
|
||||
new_debug_strings = false;
|
||||
pending = 0;
|
||||
|
||||
connect(&stepTrigger, SIGNAL(timeout()), SLOT(doNextStepSlot()));
|
||||
stepTrigger.setSingleShot(true);
|
||||
|
||||
connect(&debugTrigger, SIGNAL(timeout()), SLOT(doDebug()));
|
||||
debugTrigger.setSingleShot(true);
|
||||
|
||||
connect(&stepTimeout, SIGNAL(timeout()), SLOT(st_timeout()));
|
||||
stepTimeout.setSingleShot(true);
|
||||
|
||||
my_srand();
|
||||
|
||||
clock.start();
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(sess)
|
||||
{
|
||||
jdns_session_delete(sess);
|
||||
sess = 0;
|
||||
}
|
||||
shutting_down = false;
|
||||
pending = 0;
|
||||
qDeleteAll(socketForHandle);
|
||||
socketForHandle.clear();
|
||||
handleForSocket.clear();
|
||||
stepTrigger.stop();
|
||||
stepTimeout.stop();
|
||||
need_handle = 0;
|
||||
}
|
||||
|
||||
bool init(QJDns::Mode _mode, const QHostAddress &address)
|
||||
{
|
||||
mode = _mode;
|
||||
|
||||
jdns_callbacks_t callbacks;
|
||||
callbacks.app = this;
|
||||
callbacks.time_now = cb_time_now;
|
||||
callbacks.rand_int = cb_rand_int;
|
||||
callbacks.debug_line = cb_debug_line;
|
||||
callbacks.udp_bind = cb_udp_bind;
|
||||
callbacks.udp_unbind = cb_udp_unbind;
|
||||
callbacks.udp_read = cb_udp_read;
|
||||
callbacks.udp_write = cb_udp_write;
|
||||
sess = jdns_session_new(&callbacks);
|
||||
next_handle = 1;
|
||||
need_handle = false;
|
||||
|
||||
int ret;
|
||||
|
||||
jdns_address_t *baddr = qt2addr(address);
|
||||
if(mode == Unicast)
|
||||
{
|
||||
ret = jdns_init_unicast(sess, baddr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
jdns_address_t *maddr;
|
||||
if(address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
maddr = jdns_address_multicast6_new();
|
||||
else
|
||||
maddr = jdns_address_multicast4_new();
|
||||
ret = jdns_init_multicast(sess, baddr, JDNS_MULTICAST_PORT, maddr);
|
||||
jdns_address_delete(maddr);
|
||||
}
|
||||
jdns_address_delete(baddr);
|
||||
|
||||
if(!ret)
|
||||
{
|
||||
jdns_session_delete(sess);
|
||||
sess = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void setNameServers(const QList<NameServer> &nslist)
|
||||
{
|
||||
jdns_nameserverlist_t *addrs = jdns_nameserverlist_new();
|
||||
for(int n = 0; n < nslist.count(); ++n)
|
||||
{
|
||||
jdns_address_t *addr = qt2addr(nslist[n].address);
|
||||
jdns_nameserverlist_append(addrs, addr, nslist[n].port);
|
||||
jdns_address_delete(addr);
|
||||
}
|
||||
jdns_set_nameservers(sess, addrs);
|
||||
jdns_nameserverlist_delete(addrs);
|
||||
}
|
||||
|
||||
void process()
|
||||
{
|
||||
if(!stepTrigger.isActive())
|
||||
{
|
||||
stepTimeout.stop();
|
||||
stepTrigger.start();
|
||||
}
|
||||
}
|
||||
|
||||
void processDebug()
|
||||
{
|
||||
new_debug_strings = true;
|
||||
if(!debugTrigger.isActive())
|
||||
debugTrigger.start();
|
||||
}
|
||||
|
||||
void doNextStep()
|
||||
{
|
||||
if(shutting_down && complete_shutdown)
|
||||
{
|
||||
cleanup();
|
||||
emit q->shutdownFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
QPointer<QObject> self = this;
|
||||
|
||||
int ret = jdns_step(sess);
|
||||
|
||||
QList<LateError> errors;
|
||||
QList<int> published;
|
||||
QList<LateResponse> responses;
|
||||
bool finish_shutdown = false;
|
||||
|
||||
while(1)
|
||||
{
|
||||
jdns_event_t *e = jdns_next_event(sess);
|
||||
if(!e)
|
||||
break;
|
||||
|
||||
if(e->type == JDNS_EVENT_SHUTDOWN)
|
||||
{
|
||||
finish_shutdown = true;
|
||||
}
|
||||
else if(e->type == JDNS_EVENT_PUBLISH)
|
||||
{
|
||||
if(e->status != JDNS_STATUS_SUCCESS)
|
||||
{
|
||||
QJDns::Error error;
|
||||
if(e->status == JDNS_STATUS_CONFLICT)
|
||||
error = QJDns::ErrorConflict;
|
||||
else
|
||||
error = QJDns::ErrorGeneric;
|
||||
LateError le;
|
||||
le.id = e->id;
|
||||
le.error = error;
|
||||
errors += le;
|
||||
}
|
||||
else
|
||||
{
|
||||
published += e->id;
|
||||
}
|
||||
}
|
||||
else if(e->type == JDNS_EVENT_RESPONSE)
|
||||
{
|
||||
if(e->status != JDNS_STATUS_SUCCESS)
|
||||
{
|
||||
QJDns::Error error;
|
||||
if(e->status == JDNS_STATUS_NXDOMAIN)
|
||||
error = QJDns::ErrorNXDomain;
|
||||
else if(e->status == JDNS_STATUS_TIMEOUT)
|
||||
error = QJDns::ErrorTimeout;
|
||||
else
|
||||
error = QJDns::ErrorGeneric;
|
||||
LateError le;
|
||||
le.id = e->id;
|
||||
le.error = error;
|
||||
errors += le;
|
||||
}
|
||||
else
|
||||
{
|
||||
QJDns::Response out_response;
|
||||
for(int n = 0; n < e->response->answerCount; ++n)
|
||||
out_response.answerRecords += import_record(e->response->answerRecords[n]);
|
||||
LateResponse lr;
|
||||
lr.id = e->id;
|
||||
lr.response = out_response;
|
||||
responses += lr;
|
||||
}
|
||||
}
|
||||
|
||||
jdns_event_delete(e);
|
||||
}
|
||||
|
||||
if(ret & JDNS_STEP_TIMER)
|
||||
stepTimeout.start(jdns_next_timer(sess));
|
||||
else
|
||||
stepTimeout.stop();
|
||||
|
||||
need_handle = (ret & JDNS_STEP_HANDLE);
|
||||
|
||||
for(int n = 0; n < errors.count(); ++n)
|
||||
{
|
||||
emit q->error(errors[n].id, errors[n].error);
|
||||
if(!self)
|
||||
return;
|
||||
}
|
||||
|
||||
for(int n = 0; n < published.count(); ++n)
|
||||
{
|
||||
emit q->published(published[n]);
|
||||
if(!self)
|
||||
return;
|
||||
}
|
||||
|
||||
for(int n = 0; n < responses.count(); ++n)
|
||||
{
|
||||
emit q->resultsReady(responses[n].id, responses[n].response);
|
||||
if(!self)
|
||||
return;
|
||||
}
|
||||
|
||||
if(finish_shutdown)
|
||||
{
|
||||
// if we have pending udp packets to write, stick around
|
||||
if(pending > 0)
|
||||
{
|
||||
pending_wait = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
complete_shutdown = true;
|
||||
process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private slots:
|
||||
void udp_readyRead()
|
||||
{
|
||||
QUdpSocket *sock = (QUdpSocket *)sender();
|
||||
int handle = handleForSocket.value(sock);
|
||||
|
||||
if(need_handle)
|
||||
{
|
||||
jdns_set_handle_readable(sess, handle);
|
||||
process();
|
||||
}
|
||||
else
|
||||
{
|
||||
// eat packet
|
||||
QByteArray buf(4096, 0);
|
||||
QHostAddress from_addr;
|
||||
quint16 from_port;
|
||||
sock->readDatagram(buf.data(), buf.size(), &from_addr, &from_port);
|
||||
}
|
||||
}
|
||||
|
||||
void udp_bytesWritten(qint64)
|
||||
{
|
||||
if(pending > 0)
|
||||
{
|
||||
--pending;
|
||||
if(shutting_down && pending_wait && pending == 0)
|
||||
{
|
||||
pending_wait = false;
|
||||
complete_shutdown = true;
|
||||
process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void st_timeout()
|
||||
{
|
||||
doNextStep();
|
||||
}
|
||||
|
||||
void doNextStepSlot()
|
||||
{
|
||||
doNextStep();
|
||||
}
|
||||
|
||||
void doDebug()
|
||||
{
|
||||
if(new_debug_strings)
|
||||
{
|
||||
new_debug_strings = false;
|
||||
if(!debug_strings.isEmpty())
|
||||
emit q->debugLinesReady();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// jdns callbacks
|
||||
static int cb_time_now(jdns_session_t *, void *app)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
return self->clock.elapsed();
|
||||
}
|
||||
|
||||
static int cb_rand_int(jdns_session_t *, void *)
|
||||
{
|
||||
return rand() % 65536;
|
||||
}
|
||||
|
||||
static void cb_debug_line(jdns_session_t *, void *app, const char *str)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
self->debug_strings += QString::fromLatin1(str);
|
||||
self->processDebug();
|
||||
}
|
||||
|
||||
static int cb_udp_bind(jdns_session_t *, void *app, const jdns_address_t *addr, int port, const jdns_address_t *maddr)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
// we always pass non-null to jdns_init, so this should be a valid address
|
||||
QHostAddress host = addr2qt(addr);
|
||||
|
||||
QUdpSocket *sock = new QUdpSocket(self);
|
||||
self->connect(sock, SIGNAL(readyRead()), SLOT(udp_readyRead()));
|
||||
|
||||
// use queued for bytesWritten, since qt is evil and emits before writeDatagram returns
|
||||
qRegisterMetaType<qint64>("qint64");
|
||||
self->connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(udp_bytesWritten(qint64)), Qt::QueuedConnection);
|
||||
|
||||
QUdpSocket::BindMode mode;
|
||||
mode |= QUdpSocket::ShareAddress;
|
||||
mode |= QUdpSocket::ReuseAddressHint;
|
||||
if(!sock->bind(host, port, mode))
|
||||
{
|
||||
delete sock;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(maddr)
|
||||
{
|
||||
int sd = sock->socketDescriptor();
|
||||
bool ok;
|
||||
int errorCode;
|
||||
if(maddr->isIpv6)
|
||||
ok = qjdns_sock_setMulticast6(sd, maddr->addr.v6, &errorCode);
|
||||
else
|
||||
ok = qjdns_sock_setMulticast4(sd, maddr->addr.v4, &errorCode);
|
||||
|
||||
if(!ok)
|
||||
{
|
||||
delete sock;
|
||||
|
||||
self->debug_strings += QString("failed to setup multicast on the socket (errorCode=%1)").arg(errorCode);
|
||||
self->processDebug();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(maddr->isIpv6)
|
||||
{
|
||||
qjdns_sock_setTTL6(sd, 255);
|
||||
qjdns_sock_setIPv6Only(sd);
|
||||
}
|
||||
else
|
||||
qjdns_sock_setTTL4(sd, 255);
|
||||
}
|
||||
|
||||
int handle = self->next_handle++;
|
||||
self->socketForHandle.insert(handle, sock);
|
||||
self->handleForSocket.insert(sock, handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void cb_udp_unbind(jdns_session_t *, void *app, int handle)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
QUdpSocket *sock = self->socketForHandle.value(handle);
|
||||
if(!sock)
|
||||
return;
|
||||
|
||||
self->socketForHandle.remove(handle);
|
||||
self->handleForSocket.remove(sock);
|
||||
delete sock;
|
||||
}
|
||||
|
||||
static int cb_udp_read(jdns_session_t *, void *app, int handle, jdns_address_t *addr, int *port, unsigned char *buf, int *bufsize)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
QUdpSocket *sock = self->socketForHandle.value(handle);
|
||||
if(!sock)
|
||||
return 0;
|
||||
|
||||
// nothing to read?
|
||||
if(!sock->hasPendingDatagrams())
|
||||
return 0;
|
||||
|
||||
QHostAddress from_addr;
|
||||
quint16 from_port;
|
||||
int ret = sock->readDatagram((char *)buf, *bufsize, &from_addr, &from_port);
|
||||
if(ret == -1)
|
||||
return 0;
|
||||
|
||||
qt2addr_set(addr, from_addr);
|
||||
*port = (int)from_port;
|
||||
*bufsize = ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cb_udp_write(jdns_session_t *, void *app, int handle, const jdns_address_t *addr, int port, unsigned char *buf, int bufsize)
|
||||
{
|
||||
QJDns::Private *self = (QJDns::Private *)app;
|
||||
|
||||
QUdpSocket *sock = self->socketForHandle.value(handle);
|
||||
if(!sock)
|
||||
return 0;
|
||||
|
||||
QHostAddress host = addr2qt(addr);
|
||||
int ret = sock->writeDatagram((const char *)buf, bufsize, host, port);
|
||||
if(ret == -1)
|
||||
{
|
||||
// this can happen if the datagram to send is too big. i'm not sure what else
|
||||
// may cause this. if we return 0, then jdns may try to resend the packet,
|
||||
// which might not work if it is too large (causing the same error over and
|
||||
// over). we'll return success to jdns, so the result is as if the packet
|
||||
// was dropped.
|
||||
return 1;
|
||||
}
|
||||
|
||||
++self->pending;
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
QJDns::QJDns(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
QJDns::~QJDns()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool QJDns::init(Mode mode, const QHostAddress &address)
|
||||
{
|
||||
return d->init(mode, address);
|
||||
}
|
||||
|
||||
void QJDns::shutdown()
|
||||
{
|
||||
d->shutting_down = true;
|
||||
d->pending_wait = false;
|
||||
d->complete_shutdown = false;
|
||||
jdns_shutdown(d->sess);
|
||||
d->process();
|
||||
}
|
||||
|
||||
QStringList QJDns::debugLines()
|
||||
{
|
||||
QStringList tmp = d->debug_strings;
|
||||
d->debug_strings.clear();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
QJDns::SystemInfo QJDns::systemInfo()
|
||||
{
|
||||
SystemInfo out;
|
||||
jdns_dnsparams_t *params = jdns_system_dnsparams();
|
||||
for(int n = 0; n < params->nameservers->count; ++n)
|
||||
{
|
||||
NameServer ns;
|
||||
ns.address = addr2qt(params->nameservers->item[n]->address);
|
||||
out.nameServers += ns;
|
||||
}
|
||||
for(int n = 0; n < params->domains->count; ++n)
|
||||
out.domains += str2qt(params->domains->item[n]);
|
||||
for(int n = 0; n < params->hosts->count; ++n)
|
||||
{
|
||||
DnsHost h;
|
||||
h.name = str2qt(params->hosts->item[n]->name);
|
||||
h.address = addr2qt(params->hosts->item[n]->address);
|
||||
out.hosts += h;
|
||||
}
|
||||
jdns_dnsparams_delete(params);
|
||||
return out;
|
||||
}
|
||||
|
||||
#define PROBE_BASE 20000
|
||||
#define PROBE_RANGE 100
|
||||
|
||||
QHostAddress QJDns::detectPrimaryMulticast(const QHostAddress &address)
|
||||
{
|
||||
my_srand();
|
||||
|
||||
QUdpSocket *sock = new QUdpSocket;
|
||||
QUdpSocket::BindMode mode;
|
||||
mode |= QUdpSocket::ShareAddress;
|
||||
mode |= QUdpSocket::ReuseAddressHint;
|
||||
int port = -1;
|
||||
for(int n = 0; n < PROBE_RANGE; ++n)
|
||||
{
|
||||
if(sock->bind(address, PROBE_BASE + n, mode))
|
||||
{
|
||||
port = PROBE_BASE + n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(port == -1)
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
|
||||
jdns_address_t *a;
|
||||
if(address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
a = jdns_address_multicast6_new();
|
||||
else
|
||||
a = jdns_address_multicast4_new();
|
||||
QHostAddress maddr = addr2qt(a);
|
||||
jdns_address_delete(a);
|
||||
|
||||
if(address.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
{
|
||||
int x;
|
||||
if(!qjdns_sock_setMulticast6(sock->socketDescriptor(), maddr.toIPv6Address().c, &x))
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
qjdns_sock_setTTL6(sock->socketDescriptor(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int x;
|
||||
if(!qjdns_sock_setMulticast4(sock->socketDescriptor(), maddr.toIPv4Address(), &x))
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
qjdns_sock_setTTL4(sock->socketDescriptor(), 0);
|
||||
}
|
||||
|
||||
QHostAddress result;
|
||||
QByteArray out(128, 0);
|
||||
for(int n = 0; n < out.size(); ++n)
|
||||
out[n] = rand();
|
||||
if(sock->writeDatagram(out.data(), out.size(), maddr, port) == -1)
|
||||
{
|
||||
delete sock;
|
||||
return QHostAddress();
|
||||
}
|
||||
while(1)
|
||||
{
|
||||
sock->waitForReadyRead(-1);
|
||||
QByteArray in(128, 0);
|
||||
QHostAddress from_addr;
|
||||
quint16 from_port;
|
||||
int ret = sock->readDatagram(in.data(), in.size(), &from_addr, &from_port);
|
||||
if(ret == -1)
|
||||
continue;
|
||||
if(from_port != port)
|
||||
continue;
|
||||
in.resize(ret);
|
||||
if(in.size() != out.size())
|
||||
continue;
|
||||
bool ok = true;
|
||||
for(int n = 0; n < in.size(); ++n)
|
||||
{
|
||||
if(in[n] != out[n])
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!ok)
|
||||
continue;
|
||||
|
||||
result = from_addr;
|
||||
break;
|
||||
}
|
||||
delete sock;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void QJDns::setNameServers(const QList<NameServer> &list)
|
||||
{
|
||||
d->setNameServers(list);
|
||||
}
|
||||
|
||||
int QJDns::queryStart(const QByteArray &name, int type)
|
||||
{
|
||||
int id = jdns_query(d->sess, (const unsigned char *)name.data(), type);
|
||||
d->process();
|
||||
return id;
|
||||
}
|
||||
|
||||
void QJDns::queryCancel(int id)
|
||||
{
|
||||
jdns_cancel_query(d->sess, id);
|
||||
d->process();
|
||||
}
|
||||
|
||||
int QJDns::publishStart(PublishMode m, const Record &record)
|
||||
{
|
||||
jdns_rr_t *rr = export_record(record);
|
||||
|
||||
int pubmode;
|
||||
if(m == QJDns::Unique)
|
||||
pubmode = JDNS_PUBLISH_UNIQUE;
|
||||
else
|
||||
pubmode = JDNS_PUBLISH_SHARED;
|
||||
|
||||
int id = jdns_publish(d->sess, pubmode, rr);
|
||||
jdns_rr_delete(rr);
|
||||
d->process();
|
||||
return id;
|
||||
}
|
||||
|
||||
void QJDns::publishUpdate(int id, const Record &record)
|
||||
{
|
||||
jdns_rr_t *rr = export_record(record);
|
||||
|
||||
jdns_update_publish(d->sess, id, rr);
|
||||
jdns_rr_delete(rr);
|
||||
d->process();
|
||||
}
|
||||
|
||||
void QJDns::publishCancel(int id)
|
||||
{
|
||||
jdns_cancel_publish(d->sess, id);
|
||||
d->process();
|
||||
}
|
||||
|
||||
#include "qjdns.moc"
|
||||
158
iris-legacy/iris/irisnet/jdns/qjdns.h
Normal file
158
iris-legacy/iris/irisnet/jdns/qjdns.h
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// this is the Qt wrapper to jdns. it requires Qt 4.1+
|
||||
|
||||
#ifndef QJDNS_H
|
||||
#define QJDNS_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
|
||||
class QJDns : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
Unicast,
|
||||
Multicast
|
||||
};
|
||||
|
||||
enum PublishMode
|
||||
{
|
||||
Unique,
|
||||
Shared
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
A = 1,
|
||||
Aaaa = 28,
|
||||
Mx = 15,
|
||||
Srv = 33,
|
||||
Cname = 5,
|
||||
Ptr = 12,
|
||||
Txt = 16,
|
||||
Hinfo = 13,
|
||||
Ns = 2,
|
||||
Any = 255
|
||||
};
|
||||
|
||||
enum Error
|
||||
{
|
||||
ErrorGeneric,
|
||||
ErrorNXDomain, // query only
|
||||
ErrorTimeout, // query only
|
||||
ErrorConflict // publish only
|
||||
};
|
||||
|
||||
class NameServer
|
||||
{
|
||||
public:
|
||||
QHostAddress address;
|
||||
int port;
|
||||
|
||||
NameServer();
|
||||
};
|
||||
|
||||
class DnsHost
|
||||
{
|
||||
public:
|
||||
QByteArray name;
|
||||
QHostAddress address;
|
||||
};
|
||||
|
||||
class SystemInfo
|
||||
{
|
||||
public:
|
||||
QList<NameServer> nameServers;
|
||||
QList<QByteArray> domains;
|
||||
QList<DnsHost> hosts;
|
||||
};
|
||||
|
||||
class Record
|
||||
{
|
||||
public:
|
||||
QByteArray owner;
|
||||
int ttl;
|
||||
int type;
|
||||
QByteArray rdata;
|
||||
bool haveKnown;
|
||||
|
||||
// known
|
||||
QHostAddress address; // for A, Aaaa
|
||||
QByteArray name; // for Mx, Srv, Cname, Ptr, Ns
|
||||
int priority; // for Mx, Srv
|
||||
int weight; // for Srv
|
||||
int port; // for Srv
|
||||
QList<QByteArray> texts; // for Txt
|
||||
QByteArray cpu; // for Hinfo
|
||||
QByteArray os; // for Hinfo
|
||||
|
||||
Record();
|
||||
bool verify() const;
|
||||
};
|
||||
|
||||
class Response
|
||||
{
|
||||
public:
|
||||
QList<Record> answerRecords;
|
||||
QList<Record> authorityRecords;
|
||||
QList<Record> additionalRecords;
|
||||
};
|
||||
|
||||
QJDns(QObject *parent = 0);
|
||||
~QJDns();
|
||||
|
||||
bool init(Mode mode, const QHostAddress &address);
|
||||
void shutdown();
|
||||
QStringList debugLines();
|
||||
|
||||
static SystemInfo systemInfo();
|
||||
static QHostAddress detectPrimaryMulticast(const QHostAddress &address);
|
||||
|
||||
void setNameServers(const QList<NameServer> &list);
|
||||
|
||||
int queryStart(const QByteArray &name, int type);
|
||||
void queryCancel(int id);
|
||||
|
||||
// for multicast mode only
|
||||
int publishStart(PublishMode m, const Record &record);
|
||||
void publishUpdate(int id, const Record &record);
|
||||
void publishCancel(int id);
|
||||
|
||||
signals:
|
||||
void resultsReady(int id, const QJDns::Response &results);
|
||||
void published(int id);
|
||||
void error(int id, QJDns::Error e);
|
||||
void shutdownFinished();
|
||||
void debugLinesReady();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
#endif
|
||||
184
iris-legacy/iris/irisnet/jdns/qjdns_sock.cpp
Normal file
184
iris-legacy/iris/irisnet/jdns/qjdns_sock.cpp
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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 "qjdns_sock.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <winsock2.h>
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
# include <signal.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifndef QT_NO_IPV6
|
||||
# define HAVE_IPV6
|
||||
# ifndef IPPROTO_IPV6
|
||||
# define IPPROTO_IPV6 41
|
||||
struct in6_addr
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char _S6_u8[16];
|
||||
unsigned short _S6_u16[8];
|
||||
unsigned long _S6_u32[4];
|
||||
} _S6_un;
|
||||
};
|
||||
# define s6_addr _S6_un._S6_u8
|
||||
# endif
|
||||
# ifndef IPV6_JOIN_GROUP
|
||||
# define IPV6_JOIN_GROUP 12
|
||||
# define IPV6_MULTICAST_HOPS 10
|
||||
struct ipv6_mreq
|
||||
{
|
||||
struct in6_addr ipv6mr_multiaddr;
|
||||
unsigned int ipv6mr_interface;
|
||||
};
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static int get_last_error()
|
||||
{
|
||||
int x;
|
||||
#ifdef Q_OS_WIN
|
||||
x = WSAGetLastError();
|
||||
#else
|
||||
x = errno;
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
bool qjdns_sock_setMulticast4(int s, unsigned long int addr, int *errorCode)
|
||||
{
|
||||
int ret;
|
||||
struct ip_mreq mc;
|
||||
|
||||
memset(&mc, 0, sizeof(mc));
|
||||
mc.imr_multiaddr.s_addr = htonl(addr);
|
||||
mc.imr_interface.s_addr = INADDR_ANY;
|
||||
|
||||
ret = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char *)&mc, sizeof(mc));
|
||||
if(ret != 0)
|
||||
{
|
||||
if(errorCode)
|
||||
*errorCode = get_last_error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qjdns_sock_setMulticast6(int s, unsigned char *addr, int *errorCode)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
int ret;
|
||||
struct ipv6_mreq mc;
|
||||
|
||||
memset(&mc, 0, sizeof(mc));
|
||||
memcpy(mc.ipv6mr_multiaddr.s6_addr, addr, 16);
|
||||
mc.ipv6mr_interface = 0;
|
||||
|
||||
ret = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char *)&mc, sizeof(mc));
|
||||
if(ret != 0)
|
||||
{
|
||||
if(errorCode)
|
||||
*errorCode = get_last_error();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(s);
|
||||
Q_UNUSED(addr);
|
||||
Q_UNUSED(errorCode);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool qjdns_sock_setTTL4(int s, int ttl)
|
||||
{
|
||||
unsigned char cttl;
|
||||
int ret, ittl;
|
||||
|
||||
cttl = ttl;
|
||||
ittl = ttl;
|
||||
|
||||
// IP_MULTICAST_TTL might take 1 byte or 4, try both
|
||||
ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&cttl, sizeof(cttl));
|
||||
if(ret != 0)
|
||||
{
|
||||
ret = setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&ittl, sizeof(ittl));
|
||||
if(ret != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qjdns_sock_setTTL6(int s, int ttl)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
unsigned char cttl;
|
||||
int ret, ittl;
|
||||
|
||||
cttl = ttl;
|
||||
ittl = ttl;
|
||||
|
||||
// IPV6_MULTICAST_HOPS might take 1 byte or 4, try both
|
||||
ret = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&cttl, sizeof(cttl));
|
||||
if(ret != 0)
|
||||
{
|
||||
ret = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&ittl, sizeof(ittl));
|
||||
if(ret != 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(s);
|
||||
Q_UNUSED(ttl);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool qjdns_sock_setIPv6Only(int s)
|
||||
{
|
||||
#if defined(HAVE_IPV6) && defined(IPV6_V6ONLY)
|
||||
int x = 1;
|
||||
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&x, sizeof(x)) != 0)
|
||||
return false;
|
||||
return true;
|
||||
#else
|
||||
Q_UNUSED(s);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
33
iris-legacy/iris/irisnet/jdns/qjdns_sock.h
Normal file
33
iris-legacy/iris/irisnet/jdns/qjdns_sock.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2005,2006 Justin Karneges
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef QJDNS_SOCK_H
|
||||
#define QJDNS_SOCK_H
|
||||
|
||||
bool qjdns_sock_setMulticast4(int s, unsigned long int addr, int *errorCode);
|
||||
bool qjdns_sock_setMulticast6(int s, unsigned char *addr, int *errorCode);
|
||||
bool qjdns_sock_setTTL4(int s, int ttl);
|
||||
bool qjdns_sock_setTTL6(int s, int ttl);
|
||||
bool qjdns_sock_setIPv6Only(int s);
|
||||
|
||||
#endif
|
||||
1201
iris-legacy/iris/irisnet/jdnsshared.cpp
Normal file
1201
iris-legacy/iris/irisnet/jdnsshared.cpp
Normal file
File diff suppressed because it is too large
Load diff
511
iris-legacy/iris/irisnet/jdnsshared.h
Normal file
511
iris-legacy/iris/irisnet/jdnsshared.h
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
/*
|
||||
* Copyright (C) 2006,2007 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef JDNSSHARED_H
|
||||
#define JDNSSHARED_H
|
||||
|
||||
#include "jdns/qjdns.h"
|
||||
|
||||
class JDnsShared;
|
||||
class JDnsSharedPrivate;
|
||||
class JDnsSharedRequestPrivate;
|
||||
class JDnsSharedDebugPrivate;
|
||||
|
||||
/**
|
||||
\brief Collects debugging information from JDnsShared
|
||||
|
||||
\note Iris users should utilize NetNames for DNS capabilities, <i>not</i> JDnsSharedDebug. See the JDnsShared documentation for more information.
|
||||
|
||||
JDnsSharedDebug is used to collect debugging information from one or many JDnsShared objects. To use it, simply create it and pass it to JDnsShared::setDebug().
|
||||
|
||||
Example use:
|
||||
|
||||
\code
|
||||
JDnsSharedDebug *db = new JDnsSharedDebug;
|
||||
connect(db, SIGNAL(debugLinesReady(const QStringList &)),
|
||||
SLOT(db_debugLinesReady(const QStringList &)));
|
||||
|
||||
JDnsShared *jdnsShared1 = new JDnsShared(JDnsShared::UnicastInternet);
|
||||
jdnsShared1->setDebug(db, "U");
|
||||
|
||||
JDnsShared *jdnsShared2 = new JDnsShared(JDnsShared::UnicastLocal);
|
||||
jdnsShared2->setDebug(db, "L");
|
||||
...
|
||||
void db_debugLinesReady(const QStringList &lines)
|
||||
{
|
||||
foreach(QString line, lines)
|
||||
printf("%s\n", qPrintable(line));
|
||||
}
|
||||
\endcode
|
||||
|
||||
JDnsShared reports debug lines with the name and interface number prepended to each line. For example, if there is debug information to report about the second interface added to \a jdnsShared2 in the above example, the lines would be prepended with "L1: ".
|
||||
|
||||
Do not destroy JDnsSharedDebug until all of the JDnsShared objects associated with it have been destroyed.
|
||||
|
||||
\sa JDnsShared JDnsSharedRequest
|
||||
*/
|
||||
class JDnsSharedDebug : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief Constructs a new object with the given \a parent
|
||||
*/
|
||||
JDnsSharedDebug(QObject *parent = 0);
|
||||
|
||||
/**
|
||||
\brief Destroys the object
|
||||
*/
|
||||
~JDnsSharedDebug();
|
||||
|
||||
/**
|
||||
\brief Read the available debug information
|
||||
|
||||
Debug information is reported as a series of lines. The lines are of reasonable length, and so if you're storing a backlog of the most recent debug information, it should be safe to make the cut-off point based on lines.
|
||||
|
||||
\sa readyRead
|
||||
*/
|
||||
QStringList readDebugLines();
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Emitted when there is debug information to report
|
||||
|
||||
\sa readDebugLines
|
||||
*/
|
||||
void readyRead();
|
||||
|
||||
private:
|
||||
friend class JDnsShared;
|
||||
friend class JDnsSharedPrivate;
|
||||
friend class JDnsSharedDebugPrivate;
|
||||
JDnsSharedDebugPrivate *d;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Performs a DNS operation using JDnsShared
|
||||
|
||||
\note Iris users should utilize NetNames for DNS capabilities, <i>not</i> JDnsSharedRequest. See the JDnsShared documentation for more information.
|
||||
|
||||
JDnsSharedRequest is used to perform DNS operations on a JDnsShared object. Many requests may be performed simultaneously, such that a single JDnsShared object can be "shared" across the application. Please see the JDnsShared documentation for more complete information about how the overall system works.
|
||||
|
||||
Call query() to perform a query. Call publish() (or publishUpdate()) to make DNS records available on the local network (JDnsShared::Multicast mode only). When the operation has something to report, the resultsReady() signal is emitted. Call success() to determine the status of the operation. If success() returns false, then the operation has failed and the reason for the failure can be determined with error(). If success() returns true, then the meaning differs depending on the type of operation being performed:
|
||||
<ul>
|
||||
<li>For JDnsShared::UnicastInternet and JDnsShared::UnicastLocal modes, call results() to obtain the records obtained by the query. In these modes, resultsReady() is only emitted once, at which point the operation is no longer active.</li>
|
||||
<li>For JDnsShared::Multicast, operations are long-lived. Query operations never timeout, and resultsReady() may be emitted multiple times. In order to stop the query, either call cancel() or destroy the JDnsSharedRequest object. Similarly, publishing is long-lived. The record stays published as long as the JDnsSharedRequest has not been cancelled or destroyed.</li>
|
||||
</ul>
|
||||
|
||||
Here is how you might look up an A record:
|
||||
|
||||
\code
|
||||
JDnsSharedRequest *req = new JDnsSharedRequest(jdnsShared);
|
||||
connect(req, SIGNAL(resultsReady()), SLOT(req_resultsReady()));
|
||||
req->query("psi-im.org", QJDns::A);
|
||||
...
|
||||
void req_resultsReady()
|
||||
{
|
||||
if(req->success())
|
||||
{
|
||||
// print all of the IP addresses obtained
|
||||
QList<QJDns::Record> results = req->results();
|
||||
foreach(QJDns::Record r, results)
|
||||
{
|
||||
if(r.type == QJDns::A)
|
||||
printf("%s\n", qPrintable(r.address.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("Error resolving!\n");
|
||||
}
|
||||
\endcode
|
||||
|
||||
Here is an example of publishing a record:
|
||||
|
||||
\code
|
||||
JDnsSharedRequest *pub = new JDnsSharedRequest(jdnsShared);
|
||||
connect(pub, SIGNAL(resultsReady()), SLOT(pub_resultsReady()));
|
||||
|
||||
// let's publish an A record
|
||||
QJDns::Record rec;
|
||||
rec.owner = "SomeComputer.local.";
|
||||
rec.type = QJDns::A;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = QHostAddress("192.168.0.32");
|
||||
|
||||
pub->publish(QJDns::Unique, rec);
|
||||
...
|
||||
void pub_resultsReady()
|
||||
{
|
||||
if(pub->success())
|
||||
printf("Record published\n");
|
||||
else
|
||||
printf("Error publishing!\n");
|
||||
}
|
||||
\endcode
|
||||
|
||||
To update an existing record, use publishUpdate():
|
||||
|
||||
\code
|
||||
// the IP address of the host changed, so make a new record
|
||||
QJDns::Record rec;
|
||||
rec.owner = "SomeComputer.local.";
|
||||
rec.type = QJDns::A;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = QHostAddress("192.168.0.64");
|
||||
|
||||
// update it
|
||||
pub->publishUpdate(rec);
|
||||
\endcode
|
||||
|
||||
As a special exception, the address value can be left unspecified for A and Aaaa record types, which tells JDnsShared to substitute the address value with the address of whatever interfaces the record gets published on. This is the preferred way to publish the IP address of your own machine, and in fact it is the only way to do so if you have multiple interfaces, because there will likely be a different IP address value for each interface (the record resolves to a different answer depending on which interface a query comes from).
|
||||
|
||||
\code
|
||||
// let's publish our own A record
|
||||
QJDns::Record rec;
|
||||
rec.owner = "MyComputer.local.";
|
||||
rec.type = QJDns::A;
|
||||
rec.ttl = 120;
|
||||
rec.haveKnown = true;
|
||||
rec.address = QHostAddress();
|
||||
|
||||
pub->publish(QJDns::Unique, rec);
|
||||
\endcode
|
||||
|
||||
When you want to unpublish, call cancel() or destroy the JDnsSharedRequest.
|
||||
|
||||
\sa JDnsShared
|
||||
*/
|
||||
class JDnsSharedRequest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief Operation type
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
Query, ///< Query operation, initiated by query()
|
||||
Publish ///< Publish operation, initiated by publish() or publishUpdate()
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Request error
|
||||
*/
|
||||
enum Error
|
||||
{
|
||||
ErrorNoNet, ///< There are no available network interfaces to operate on. This happens if JDnsShared::addInterface() was not called.
|
||||
ErrorGeneric, ///< Generic error during the operation.
|
||||
ErrorNXDomain, ///< The name looked up does not exist.
|
||||
ErrorTimeout, ///< The operation timed out.
|
||||
ErrorConflict ///< Attempt to publish an already published unique record.
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Constructs a new object with the given \a jdnsShared and \a parent
|
||||
*/
|
||||
JDnsSharedRequest(JDnsShared *jdnsShared, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
\brief Destroys the object
|
||||
|
||||
If there is an active operation, it is cancelled.
|
||||
*/
|
||||
~JDnsSharedRequest();
|
||||
|
||||
/**
|
||||
\brief The type of operation being performed
|
||||
*/
|
||||
Type type();
|
||||
|
||||
/**
|
||||
\brief Perform a query operation
|
||||
*/
|
||||
void query(const QByteArray &name, int type);
|
||||
|
||||
/**
|
||||
\brief Perform a publish operation
|
||||
*/
|
||||
void publish(QJDns::PublishMode m, const QJDns::Record &record);
|
||||
|
||||
/**
|
||||
\brief Update a record that is currently published
|
||||
*/
|
||||
void publishUpdate(const QJDns::Record &record);
|
||||
|
||||
/**
|
||||
\brief Cancels the current operation
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
\brief Indicates whether or not the operation was successful
|
||||
*/
|
||||
bool success() const;
|
||||
|
||||
/**
|
||||
\brief Returns the reason for error
|
||||
*/
|
||||
Error error() const;
|
||||
|
||||
/**
|
||||
\brief Returns the results of the operation
|
||||
*/
|
||||
QList<QJDns::Record> results() const;
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Indicates that the operation has something to report
|
||||
|
||||
After receiving this signal, call success() to check on the status of the operation, followed by results() or error() as appropriate.
|
||||
*/
|
||||
void resultsReady();
|
||||
|
||||
private:
|
||||
friend class JDnsShared;
|
||||
friend class JDnsSharedPrivate;
|
||||
friend class JDnsSharedRequestPrivate;
|
||||
JDnsSharedRequestPrivate *d;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Abstraction layer on top of QJDns
|
||||
|
||||
\note Iris users should utilize NetNames for DNS capabilities, <i>not</i> JDnsShared. JDnsShared is provided for non-Iris users (and it is also used internally by NetNames). To use JDnsShared by itself, simply drop the jdnsshared.h and jdnsshared.cpp files, along with JDNS, into your project. It is not a full replacement for Qt's Q3Dns, as some tasks are left to you, but it covers most of it.
|
||||
|
||||
QJDns supports everything a typical application should ever need in DNS. However, it is expected that modern applications will need to maintain multiple QJDns instances at the same time, and this is where things can get complicated. For example, most applications will want at least two QJDns instances: one for IPv4 unicast and one for IPv6 unicast.
|
||||
|
||||
A single JDnsShared object encapsulates multiple instances of QJDns that are related. For example, an IPv4 unicast instance and an IPv6 unicast instance could be coupled within JDnsShared. Then, when a unicast operation is performed on the JDnsShared object, both underlying instances will be queried as appropriate. The application itself would not need to perform two resolutions itself, nor deal with any related complexity.
|
||||
|
||||
Further, individual operations are performed using a separate class called JDnsSharedRequest, eliminating the need for the application to directly interface with a central QJDns object or track integer handles. This makes it easier for individual parts of the application to "share" the same instance (or set of instances) of QJDns, hence the name.
|
||||
|
||||
JDnsShared is a thin abstraction. QJDns subtypes (e.g. QJDns::Record, QJDns::NameServer, etc) are still used with JDnsShared. Because of the duplication of documentation effort between NetNames and QJDns, there is no formal documentation for QJDns. Users of JDnsShared will need to read qjdns.h, although a basic explanation of the elements can be found below.
|
||||
|
||||
Types:
|
||||
<table>
|
||||
<tr><td>QJDns::Type</td><td>This is a convenience enumeration for common DNS record types. For example: A, Aaaa, Srv, etc. The values directly map to the integer values of the DNS protocol (e.g. Srv = 33). See qjdns.h for all of the types and values.</td></tr>
|
||||
<tr><td>QJDns::Record</td><td>This class holds a DNS record. The main fields are <i>type</i> (integer type, probably something listed in QJDns::Type), <i>rdata</i> (QByteArray of the record value), and <i>haveKnown</i> (boolean to indicate if a decoded form of the record value is also available). See qjdns.h for the possible known fields. You will most-likely always work with known types. Received records that have a type listed in QJDns::Type are guaranteed to be known and will provide a decoded value. If you are creating a record for publishing, you will need to set <i>owner</i>, <i>ttl</i>, and <i>type</i>. If the type to be published is listed in QJDns::Type, then you will need to set <i>haveKnown</i> to true and set the known fields as appropriate, otherwise you need to set <i>rdata</i>. You do not need to supply an encoded form in <i>rdata</i> for known types, it can be left empty in that case.</td></tr>
|
||||
<tr><td>QJDns::PublishMode</td><td>This is for Multicast DNS, and can either be Unique or Shared. A shared record can be published by multiple owners (for example, a "_ssh._tcp.local." PTR record might resolve to many different SSH services owned by different machines). A unique record can only have one owner (for example, a "mycomputer.local." A record would resolve to the IP address of the machine that published it). Attempting to publish a record on a network where a unique record is already present will result in a conflict error.</td></tr>
|
||||
</table>
|
||||
|
||||
Functions:
|
||||
<table>
|
||||
<tr><td>QJDns::detectPrimaryMulticast()</td><td>Detects a multicast interface. Pass QHostAddress::Any or QHostAddress::AnyIPv6, depending on which type of interface is desired.</td></tr>
|
||||
</table>
|
||||
|
||||
To use JDnsShared, first create an instance of it, set it up by calling addInterface() as necessary, and then use JDnsSharedRequest to perform operations on it.
|
||||
|
||||
Here is an example of how to create and set up a JDnsShared object for typical DNS resolution:
|
||||
|
||||
\code
|
||||
// construct
|
||||
JDnsShared *dns = new JDnsShared(JDnsShared::UnicastInternet);
|
||||
|
||||
// add IPv4 and IPv6 interfaces
|
||||
dns->addInterface(QHostAddress::Any);
|
||||
dns->addInterface(QHostAddress::AnyIPv6);
|
||||
|
||||
// at this point, the object is ready for operation
|
||||
\endcode
|
||||
|
||||
Perform a resolution like this:
|
||||
|
||||
\code
|
||||
JDnsSharedRequest *req = new JDnsSharedRequest(dns);
|
||||
connect(req, SIGNAL(resultsReady()), SLOT(req_resultsReady()));
|
||||
req->query("psi-im.org", QJDns::A);
|
||||
...
|
||||
void req_resultsReady()
|
||||
{
|
||||
if(req->success())
|
||||
{
|
||||
// print all of the IP addresses obtained
|
||||
QList<QJDns::Record> results = req->results();
|
||||
foreach(QJDns::Record r, results)
|
||||
{
|
||||
if(r.type == QJDns::A)
|
||||
printf("%s\n", qPrintable(r.address.toString());
|
||||
}
|
||||
}
|
||||
else
|
||||
printf("Error resolving!\n");
|
||||
}
|
||||
\endcode
|
||||
|
||||
It is important to filter the results as shown in the above example. QJDns guarantees at least one record in the results will be of the type queried for, but there may also be CNAME records present (of course, if the query was for a CNAME type, then the results will only be CNAME records). The recommended approach is to simply filter for the record types desired, as shown, rather than single out CNAME specifically.
|
||||
|
||||
When you are finished with a JDnsShared object, it should be shut down before deleting:
|
||||
|
||||
\code
|
||||
connect(dns, SIGNAL(shutdownFinished()), SLOT(dns_shutdownFinished()));
|
||||
dns->shutdown();
|
||||
...
|
||||
void dns_shutdownFinished()
|
||||
{
|
||||
delete dns;
|
||||
}
|
||||
\endcode
|
||||
|
||||
Setting up JDnsShared for UnicastLocal and Multicast mode is done the same way as with UnicastInternet.
|
||||
|
||||
For example, here is how Multicast mode could be set up:
|
||||
|
||||
\code
|
||||
// construct
|
||||
JDnsShared *dns = new JDnsShared(JDnsShared::Multicast);
|
||||
|
||||
// add IPv4 interface
|
||||
QHostAddress addr = QJDns::detectPrimaryMulticast(QHostAddress::Any);
|
||||
dns->addInterface(addr);
|
||||
|
||||
// at this point, the object is ready for operation
|
||||
\endcode
|
||||
|
||||
JDnsShared provides a lot of functionality, but certain aspects of DNS are deemed out of its scope. Below are the responsibilities of the user of JDnsShared, if a more complete DNS behavior is desired:
|
||||
<ul>
|
||||
<li>Querying for several "qualified" names. You should first query for the name as provided, and if that fails then query for name + ".domain" (for every domain the computer is in). See domains().</li>
|
||||
<li>Detecting for ".local" in the name to be queried, and using that to decide whether to query via Multicast/UnicastLocal or UnicastInternet.</li>
|
||||
<li>For zeroconf/Bonjour, keep in mind that JDnsShared only provides low-level record queries. DNS-SD and any higher layers would be your job.</li>
|
||||
</ul>
|
||||
|
||||
Using a custom DNS implementation, such as JDnsShared, has the drawback that it is difficult to take advantage of platform-specific features (for example, an OS-wide DNS cache or LDAP integration). An application strategy for normal DNS should probably be:
|
||||
<ul>
|
||||
<li>If an A or AAAA record is desired, use a native lookup.</li>
|
||||
<li>Else, if the platform has advanced DNS features already (ie, res_query), use those.</li>
|
||||
<li>Else, use JDnsShared.</li>
|
||||
</ul>
|
||||
|
||||
For Multicast DNS, awareness of the platform is doubly important. There should only be one Multicast DNS "Responder" per computer, and using JDnsShared in Multicast mode at the same time could result in a conflict. An application strategy for Multicast DNS should be:
|
||||
<ul>
|
||||
<li>If the platform has a Multicast DNS daemon installed already, use it somehow.</li>
|
||||
<li>Else, use JDnsShared.</li>
|
||||
</ul>
|
||||
|
||||
\sa JDnsSharedRequest
|
||||
*/
|
||||
class JDnsShared : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief The mode to operate in
|
||||
*/
|
||||
enum Mode
|
||||
{
|
||||
/**
|
||||
For regular DNS resolution. In this mode, lookups are performed on all interfaces, and the first returned result is used.
|
||||
*/
|
||||
UnicastInternet,
|
||||
|
||||
/**
|
||||
Perform regular DNS resolution using the Multicast DNS address. This is used to resolve large and/or known Multicast DNS names without actually multicasting anything.
|
||||
*/
|
||||
UnicastLocal,
|
||||
|
||||
/**
|
||||
Multicast DNS querying and publishing.
|
||||
|
||||
\note JDnsShared supports up to one interface for each IP version (e.g. one IPv4 interface and one IPv6 interface), and expects the default/primary multicast interface for that IP version to be used.
|
||||
*/
|
||||
Multicast
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Constructs a new object with the given \a mode and \a parent
|
||||
*/
|
||||
JDnsShared(Mode mode, QObject *parent = 0);
|
||||
|
||||
/**
|
||||
\brief Destroys the object
|
||||
*/
|
||||
~JDnsShared();
|
||||
|
||||
/**
|
||||
\brief Sets the debug object to report to
|
||||
|
||||
If a debug object is set using this function, then JDnsShared will send output text to it, prefixing each line with \a name.
|
||||
*/
|
||||
void setDebug(JDnsSharedDebug *db, const QString &name);
|
||||
|
||||
/**
|
||||
\brief Adds an interface to operate on
|
||||
|
||||
For UnicastInternet and UnicastLocal, these will almost always be QHostAddress::Any or QHostAddress::AnyIPv6 (operate on the default interface for IPv4 or IPv6, respectively).
|
||||
|
||||
For Multicast, it is expected that the default/primary multicast interface will be used here. Do not pass QHostAddress::Any (or AnyIPv6) with Multicast mode.
|
||||
|
||||
Returns true if the interface was successfully added, otherwise returns false.
|
||||
*/
|
||||
bool addInterface(const QHostAddress &addr);
|
||||
|
||||
/**
|
||||
\brief Removes a previously-added interface
|
||||
*/
|
||||
void removeInterface(const QHostAddress &addr);
|
||||
|
||||
/**
|
||||
\brief Shuts down the object
|
||||
|
||||
This operation primarily exists for Multicast mode, so that any published records have a chance to be unpublished. If the JDnsShared object is simply deleted without performing a shutdown, then published records will linger on the network until their TTLs expire.
|
||||
|
||||
When shutdown is complete, the shutdownFinished() signal will be emitted.
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
\brief The domains to search in
|
||||
|
||||
You should perform a separate resolution for every domain configured on this machine.
|
||||
*/
|
||||
static QList<QByteArray> domains();
|
||||
|
||||
/**
|
||||
\brief Performs a blocking shutdown of many JDnsShared instances
|
||||
|
||||
This function is a convenient way to shutdown multiple JDnsShared instances synchronously. This function blocks, although the internal shutdown procedure uses no more than a few cycles of the eventloop, so it should be safe to call without worry of the application being overly stalled. This function takes over the instances passed to it, and will delete them upon completion.
|
||||
|
||||
Additionally, this function works without a nested eventloop. All of the JDnsShared instances are moved into a temporary thread to perform the shutdown procedure.
|
||||
|
||||
\code
|
||||
QList<JDnsShared*> list;
|
||||
list += jdnsShared_unicast;
|
||||
list += jdnsShared_multicast;
|
||||
JDnsShared::waitForShutdown(list);
|
||||
|
||||
// collect remaining debug information
|
||||
QStringList finalDebugLines = jdnsSharedDebug.readDebugLines();
|
||||
\endcode
|
||||
*/
|
||||
static void waitForShutdown(const QList<JDnsShared*> instances);
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Indicates the object has been shut down
|
||||
*/
|
||||
void shutdownFinished();
|
||||
|
||||
private:
|
||||
friend class JDnsSharedRequest;
|
||||
friend class JDnsSharedPrivate;
|
||||
JDnsSharedPrivate *d;
|
||||
};
|
||||
|
||||
#endif
|
||||
13
iris-legacy/iris/irisnet/legacy/legacy.pri
Normal file
13
iris-legacy/iris/irisnet/legacy/legacy.pri
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/safedelete.h \
|
||||
$$PWD/ndns.h \
|
||||
$$PWD/srvresolver.h \
|
||||
$$PWD/servsock.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/safedelete.cpp \
|
||||
$$PWD/ndns.cpp \
|
||||
$$PWD/srvresolver.cpp \
|
||||
$$PWD/servsock.cpp
|
||||
147
iris-legacy/iris/irisnet/legacy/ndns.cpp
Normal file
147
iris-legacy/iris/irisnet/legacy/ndns.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* ndns.cpp - native DNS resolution
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//! \class NDns ndns.h
|
||||
//! \brief Simple DNS resolution using native system calls
|
||||
//!
|
||||
//! This class is to be used when Qt's QDns is not good enough. Because QDns
|
||||
//! does not use threads, it cannot make a system call asyncronously. Thus,
|
||||
//! QDns tries to imitate the behavior of each platform's native behavior, and
|
||||
//! generally falls short.
|
||||
//!
|
||||
//! NDns uses a thread to make the system call happen in the background. This
|
||||
//! gives your program native DNS behavior, at the cost of requiring threads
|
||||
//! to build.
|
||||
//!
|
||||
//! \code
|
||||
//! #include "ndns.h"
|
||||
//!
|
||||
//! ...
|
||||
//!
|
||||
//! NDns dns;
|
||||
//! dns.resolve("psi.affinix.com");
|
||||
//!
|
||||
//! // The class will emit the resultsReady() signal when the resolution
|
||||
//! // is finished. You may then retrieve the results:
|
||||
//!
|
||||
//! QHostAddress ip_address = dns.result();
|
||||
//!
|
||||
//! // or if you want to get the IP address as a string:
|
||||
//!
|
||||
//! QString ip_address = dns.resultString();
|
||||
//! \endcode
|
||||
|
||||
#include "ndns.h"
|
||||
|
||||
#include "netnames.h"
|
||||
|
||||
// CS_NAMESPACE_BEGIN
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NDns
|
||||
//----------------------------------------------------------------------------
|
||||
//! \fn void NDns::resultsReady()
|
||||
//! This signal is emitted when the DNS resolution succeeds or fails.
|
||||
|
||||
//!
|
||||
//! Constructs an NDns object with parent \a parent.
|
||||
NDns::NDns(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
busy = false;
|
||||
|
||||
connect(&dns, SIGNAL(resultsReady(const QList<XMPP::NameRecord> &)), SLOT(dns_resultsReady(const QList<XMPP::NameRecord> &)));
|
||||
connect(&dns, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error)));
|
||||
}
|
||||
|
||||
//!
|
||||
//! Destroys the object and frees allocated resources.
|
||||
NDns::~NDns()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
//!
|
||||
//! Resolves hostname \a host (eg. psi.affinix.com)
|
||||
void NDns::resolve(const QString &host)
|
||||
{
|
||||
QHostAddress a;
|
||||
if (a.setAddress(host)) {
|
||||
addr = a;
|
||||
QMetaObject::invokeMethod(this, "resultsReady", Qt::QueuedConnection);
|
||||
}
|
||||
else {
|
||||
stop();
|
||||
busy = true;
|
||||
dns.start(host.toLatin1());
|
||||
}
|
||||
}
|
||||
|
||||
//!
|
||||
//! Cancels the lookup action.
|
||||
//! \note This will not stop the underlying system call, which must finish before the next lookup will proceed.
|
||||
void NDns::stop()
|
||||
{
|
||||
dns.stop();
|
||||
busy = false;
|
||||
}
|
||||
|
||||
//!
|
||||
//! Returns the IP address as QHostAddress. This will be a Null QHostAddress if the lookup failed.
|
||||
//! \sa resultsReady()
|
||||
QHostAddress NDns::result() const
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
|
||||
//!
|
||||
//! Returns the IP address as a string. This will be an empty string if the lookup failed.
|
||||
//! \sa resultsReady()
|
||||
QString NDns::resultString() const
|
||||
{
|
||||
if (addr.isNull())
|
||||
return QString();
|
||||
else
|
||||
return addr.toString();
|
||||
}
|
||||
|
||||
//!
|
||||
//! Returns TRUE if busy resolving a hostname.
|
||||
bool NDns::isBusy() const
|
||||
{
|
||||
return busy;
|
||||
}
|
||||
|
||||
void NDns::dns_resultsReady(const QList<XMPP::NameRecord> &results)
|
||||
{
|
||||
addr = results[0].address();
|
||||
busy = false;
|
||||
emit resultsReady();
|
||||
}
|
||||
|
||||
void NDns::dns_error(XMPP::NameResolver::Error)
|
||||
{
|
||||
addr = QHostAddress();
|
||||
busy = false;
|
||||
emit resultsReady();
|
||||
}
|
||||
|
||||
// CS_NAMESPACE_END
|
||||
|
||||
59
iris-legacy/iris/irisnet/legacy/ndns.h
Normal file
59
iris-legacy/iris/irisnet/legacy/ndns.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* ndns.h - native DNS resolution
|
||||
* Copyright (C) 2001, 2002 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CS_NDNS_H
|
||||
#define CS_NDNS_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include "netnames.h"
|
||||
|
||||
// CS_NAMESPACE_BEGIN
|
||||
|
||||
class NDns : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NDns(QObject *parent=0);
|
||||
~NDns();
|
||||
|
||||
void resolve(const QString &);
|
||||
void stop();
|
||||
bool isBusy() const;
|
||||
|
||||
QHostAddress result() const;
|
||||
QString resultString() const;
|
||||
|
||||
signals:
|
||||
void resultsReady();
|
||||
|
||||
private slots:
|
||||
void dns_resultsReady(const QList<XMPP::NameRecord> &);
|
||||
void dns_error(XMPP::NameResolver::Error);
|
||||
|
||||
private:
|
||||
XMPP::NameResolver dns;
|
||||
bool busy;
|
||||
QHostAddress addr;
|
||||
};
|
||||
|
||||
// CS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
114
iris-legacy/iris/irisnet/legacy/safedelete.cpp
Normal file
114
iris-legacy/iris/irisnet/legacy/safedelete.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#include"safedelete.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SafeDelete
|
||||
//----------------------------------------------------------------------------
|
||||
SafeDelete::SafeDelete()
|
||||
{
|
||||
lock = 0;
|
||||
}
|
||||
|
||||
SafeDelete::~SafeDelete()
|
||||
{
|
||||
if(lock)
|
||||
lock->dying();
|
||||
}
|
||||
|
||||
void SafeDelete::deleteLater(QObject *o)
|
||||
{
|
||||
if(!lock)
|
||||
deleteSingle(o);
|
||||
else
|
||||
list.append(o);
|
||||
}
|
||||
|
||||
void SafeDelete::unlock()
|
||||
{
|
||||
lock = 0;
|
||||
deleteAll();
|
||||
}
|
||||
|
||||
void SafeDelete::deleteAll()
|
||||
{
|
||||
if(list.isEmpty())
|
||||
return;
|
||||
|
||||
for(int n = 0; n < list.size(); ++n)
|
||||
deleteSingle(list[n]);
|
||||
list.clear();
|
||||
}
|
||||
|
||||
void SafeDelete::deleteSingle(QObject *o)
|
||||
{
|
||||
#if QT_VERSION < 0x030000
|
||||
// roll our own QObject::deleteLater()
|
||||
SafeDeleteLater *sdl = SafeDeleteLater::ensureExists();
|
||||
sdl->deleteItLater(o);
|
||||
#else
|
||||
o->deleteLater();
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SafeDeleteLock
|
||||
//----------------------------------------------------------------------------
|
||||
SafeDeleteLock::SafeDeleteLock(SafeDelete *sd)
|
||||
{
|
||||
own = false;
|
||||
if(!sd->lock) {
|
||||
_sd = sd;
|
||||
_sd->lock = this;
|
||||
}
|
||||
else
|
||||
_sd = 0;
|
||||
}
|
||||
|
||||
SafeDeleteLock::~SafeDeleteLock()
|
||||
{
|
||||
if(_sd) {
|
||||
_sd->unlock();
|
||||
if(own)
|
||||
delete _sd;
|
||||
}
|
||||
}
|
||||
|
||||
void SafeDeleteLock::dying()
|
||||
{
|
||||
_sd = new SafeDelete(*_sd);
|
||||
own = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SafeDeleteLater
|
||||
//----------------------------------------------------------------------------
|
||||
SafeDeleteLater *SafeDeleteLater::self = 0;
|
||||
|
||||
SafeDeleteLater *SafeDeleteLater::ensureExists()
|
||||
{
|
||||
if(!self)
|
||||
new SafeDeleteLater();
|
||||
return self;
|
||||
}
|
||||
|
||||
SafeDeleteLater::SafeDeleteLater()
|
||||
{
|
||||
self = this;
|
||||
QTimer::singleShot(0, this, SLOT(explode()));
|
||||
}
|
||||
|
||||
SafeDeleteLater::~SafeDeleteLater()
|
||||
{
|
||||
qDeleteAll(list);
|
||||
list.clear();
|
||||
self = 0;
|
||||
}
|
||||
|
||||
void SafeDeleteLater::deleteItLater(QObject *o)
|
||||
{
|
||||
list.append(o);
|
||||
}
|
||||
|
||||
void SafeDeleteLater::explode()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
59
iris-legacy/iris/irisnet/legacy/safedelete.h
Normal file
59
iris-legacy/iris/irisnet/legacy/safedelete.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef SAFEDELETE_H
|
||||
#define SAFEDELETE_H
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
class SafeDelete;
|
||||
class SafeDeleteLock
|
||||
{
|
||||
public:
|
||||
SafeDeleteLock(SafeDelete *sd);
|
||||
~SafeDeleteLock();
|
||||
|
||||
private:
|
||||
SafeDelete *_sd;
|
||||
bool own;
|
||||
friend class SafeDelete;
|
||||
void dying();
|
||||
};
|
||||
|
||||
class SafeDelete
|
||||
{
|
||||
public:
|
||||
SafeDelete();
|
||||
~SafeDelete();
|
||||
|
||||
void deleteLater(QObject *o);
|
||||
|
||||
// same as QObject::deleteLater()
|
||||
static void deleteSingle(QObject *o);
|
||||
|
||||
private:
|
||||
QObjectList list;
|
||||
void deleteAll();
|
||||
|
||||
friend class SafeDeleteLock;
|
||||
SafeDeleteLock *lock;
|
||||
void unlock();
|
||||
};
|
||||
|
||||
class SafeDeleteLater : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static SafeDeleteLater *ensureExists();
|
||||
void deleteItLater(QObject *o);
|
||||
|
||||
private slots:
|
||||
void explode();
|
||||
|
||||
private:
|
||||
SafeDeleteLater();
|
||||
~SafeDeleteLater();
|
||||
|
||||
QObjectList list;
|
||||
friend class SafeDelete;
|
||||
static SafeDeleteLater *self;
|
||||
};
|
||||
|
||||
#endif
|
||||
111
iris-legacy/iris/irisnet/legacy/servsock.cpp
Normal file
111
iris-legacy/iris/irisnet/legacy/servsock.cpp
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* servsock.cpp - simple wrapper to QServerSocket
|
||||
* Copyright (C) 2003 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "servsock.h"
|
||||
|
||||
// CS_NAMESPACE_BEGIN
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ServSock
|
||||
//----------------------------------------------------------------------------
|
||||
class ServSock::Private
|
||||
{
|
||||
public:
|
||||
Private() {}
|
||||
|
||||
ServSockSignal *serv;
|
||||
};
|
||||
|
||||
ServSock::ServSock(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private;
|
||||
d->serv = 0;
|
||||
}
|
||||
|
||||
ServSock::~ServSock()
|
||||
{
|
||||
stop();
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool ServSock::isActive() const
|
||||
{
|
||||
return (d->serv ? true: false);
|
||||
}
|
||||
|
||||
bool ServSock::listen(quint16 port)
|
||||
{
|
||||
stop();
|
||||
|
||||
d->serv = new ServSockSignal(this);
|
||||
if(!d->serv->listen(QHostAddress::Any, port)) {
|
||||
delete d->serv;
|
||||
d->serv = 0;
|
||||
return false;
|
||||
}
|
||||
connect(d->serv, SIGNAL(connectionReady(int)), SLOT(sss_connectionReady(int)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ServSock::stop()
|
||||
{
|
||||
delete d->serv;
|
||||
d->serv = 0;
|
||||
}
|
||||
|
||||
int ServSock::port() const
|
||||
{
|
||||
if(d->serv)
|
||||
return d->serv->serverPort();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
QHostAddress ServSock::address() const
|
||||
{
|
||||
if(d->serv)
|
||||
return d->serv->serverAddress();
|
||||
else
|
||||
return QHostAddress();
|
||||
}
|
||||
|
||||
void ServSock::sss_connectionReady(int s)
|
||||
{
|
||||
connectionReady(s);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ServSockSignal
|
||||
//----------------------------------------------------------------------------
|
||||
ServSockSignal::ServSockSignal(QObject *parent)
|
||||
:QTcpServer(parent)
|
||||
{
|
||||
setMaxPendingConnections(16);
|
||||
}
|
||||
|
||||
void ServSockSignal::incomingConnection(int socketDescriptor)
|
||||
{
|
||||
connectionReady(socketDescriptor);
|
||||
}
|
||||
|
||||
// CS_NAMESPACE_END
|
||||
68
iris-legacy/iris/irisnet/legacy/servsock.h
Normal file
68
iris-legacy/iris/irisnet/legacy/servsock.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* servsock.h - simple wrapper to QServerSocket
|
||||
* Copyright (C) 2003 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CS_SERVSOCK_H
|
||||
#define CS_SERVSOCK_H
|
||||
|
||||
#include <QTcpServer>
|
||||
|
||||
// CS_NAMESPACE_BEGIN
|
||||
|
||||
class ServSock : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServSock(QObject *parent=0);
|
||||
~ServSock();
|
||||
|
||||
bool isActive() const;
|
||||
bool listen(quint16 port);
|
||||
void stop();
|
||||
int port() const;
|
||||
QHostAddress address() const;
|
||||
|
||||
signals:
|
||||
void connectionReady(int);
|
||||
|
||||
private slots:
|
||||
void sss_connectionReady(int);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
class ServSockSignal : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServSockSignal(QObject *parent = 0);
|
||||
|
||||
signals:
|
||||
void connectionReady(int);
|
||||
|
||||
protected:
|
||||
// reimplemented
|
||||
void incomingConnection(int socketDescriptor);
|
||||
};
|
||||
|
||||
// CS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
298
iris-legacy/iris/irisnet/legacy/srvresolver.cpp
Normal file
298
iris-legacy/iris/irisnet/legacy/srvresolver.cpp
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* srvresolver.cpp - class to simplify SRV lookups
|
||||
* Copyright (C) 2003 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "srvresolver.h"
|
||||
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#ifndef NO_NDNS
|
||||
# include "ndns.h"
|
||||
#endif
|
||||
|
||||
// CS_NAMESPACE_BEGIN
|
||||
|
||||
bool serverLessThan(const Q3Dns::Server &s1, const Q3Dns::Server &s2)
|
||||
{
|
||||
int a = s1.priority;
|
||||
int b = s2.priority;
|
||||
int j = s1.weight;
|
||||
int k = s2.weight;
|
||||
return a < b || (a == b && j < k);
|
||||
}
|
||||
|
||||
|
||||
static void sortSRVList(QList<Q3Dns::Server> &list)
|
||||
{
|
||||
qStableSort(list.begin(), list.end(), serverLessThan);
|
||||
}
|
||||
|
||||
class SrvResolver::Private
|
||||
{
|
||||
public:
|
||||
Private() {}
|
||||
|
||||
XMPP::NameResolver nndns;
|
||||
XMPP::NameRecord::Type nntype;
|
||||
bool nndns_busy;
|
||||
|
||||
#ifndef NO_NDNS
|
||||
NDns ndns;
|
||||
#endif
|
||||
|
||||
bool failed;
|
||||
QHostAddress resultAddress;
|
||||
quint16 resultPort;
|
||||
|
||||
bool srvonly;
|
||||
QString srv;
|
||||
QList<Q3Dns::Server> servers;
|
||||
bool aaaa;
|
||||
|
||||
QTimer t;
|
||||
};
|
||||
|
||||
SrvResolver::SrvResolver(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private;
|
||||
d->nndns_busy = false;
|
||||
|
||||
connect(&d->nndns, SIGNAL(resultsReady(const QList<XMPP::NameRecord> &)), SLOT(nndns_resultsReady(const QList<XMPP::NameRecord> &)));
|
||||
connect(&d->nndns, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(nndns_error(XMPP::NameResolver::Error)));
|
||||
|
||||
#ifndef NO_NDNS
|
||||
connect(&d->ndns, SIGNAL(resultsReady()), SLOT(ndns_done()));
|
||||
#endif
|
||||
connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout()));
|
||||
stop();
|
||||
}
|
||||
|
||||
SrvResolver::~SrvResolver()
|
||||
{
|
||||
stop();
|
||||
delete d;
|
||||
}
|
||||
|
||||
void SrvResolver::resolve(const QString &server, const QString &type, const QString &proto, bool srvOnly)
|
||||
{
|
||||
stop();
|
||||
|
||||
d->failed = false;
|
||||
d->srvonly = srvOnly;
|
||||
d->srv = QString("_") + type + "._" + proto + '.' + server;
|
||||
d->t.setSingleShot(true);
|
||||
d->t.start(15000);
|
||||
d->nndns_busy = true;
|
||||
d->nntype = XMPP::NameRecord::Srv;
|
||||
d->nndns.start(d->srv.toLatin1(), d->nntype);
|
||||
}
|
||||
|
||||
void SrvResolver::resolve(const QString &server, const QString &type, const QString &proto)
|
||||
{
|
||||
resolve(server, type, proto, false);
|
||||
}
|
||||
|
||||
void SrvResolver::resolveSrvOnly(const QString &server, const QString &type, const QString &proto)
|
||||
{
|
||||
resolve(server, type, proto, true);
|
||||
}
|
||||
|
||||
void SrvResolver::next()
|
||||
{
|
||||
if(d->servers.isEmpty())
|
||||
return;
|
||||
|
||||
tryNext();
|
||||
}
|
||||
|
||||
void SrvResolver::stop()
|
||||
{
|
||||
if(d->t.isActive())
|
||||
d->t.stop();
|
||||
if(d->nndns_busy) {
|
||||
d->nndns.stop();
|
||||
d->nndns_busy = false;
|
||||
}
|
||||
#ifndef NO_NDNS
|
||||
if(d->ndns.isBusy())
|
||||
d->ndns.stop();
|
||||
#endif
|
||||
d->resultAddress = QHostAddress();
|
||||
d->resultPort = 0;
|
||||
d->servers.clear();
|
||||
d->srv = "";
|
||||
d->failed = true;
|
||||
}
|
||||
|
||||
bool SrvResolver::isBusy() const
|
||||
{
|
||||
#ifndef NO_NDNS
|
||||
if(d->nndns_busy || d->ndns.isBusy())
|
||||
#else
|
||||
if(d->nndns_busy)
|
||||
#endif
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<Q3Dns::Server> SrvResolver::servers() const
|
||||
{
|
||||
return d->servers;
|
||||
}
|
||||
|
||||
bool SrvResolver::failed() const
|
||||
{
|
||||
return d->failed;
|
||||
}
|
||||
|
||||
QHostAddress SrvResolver::resultAddress() const
|
||||
{
|
||||
return d->resultAddress;
|
||||
}
|
||||
|
||||
quint16 SrvResolver::resultPort() const
|
||||
{
|
||||
return d->resultPort;
|
||||
}
|
||||
|
||||
void SrvResolver::tryNext()
|
||||
{
|
||||
#ifndef NO_NDNS
|
||||
d->ndns.resolve(d->servers.first().name);
|
||||
#else
|
||||
d->nndns_busy = true;
|
||||
d->nntype = d->aaaa ? XMPP::NameRecord::Aaaa : XMPP::NameRecord::A;
|
||||
d->nndns.start(d->servers.first().name.toLatin1(), d->nntype);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SrvResolver::nndns_resultsReady(const QList<XMPP::NameRecord> &results)
|
||||
{
|
||||
if(!d->nndns_busy)
|
||||
return;
|
||||
|
||||
d->t.stop();
|
||||
|
||||
if(d->nntype == XMPP::NameRecord::Srv) {
|
||||
// grab the server list and destroy the qdns object
|
||||
QList<Q3Dns::Server> list;
|
||||
for(int n = 0; n < results.count(); ++n)
|
||||
{
|
||||
list += Q3Dns::Server(QString::fromLatin1(results[n].name()), results[n].priority(), results[n].weight(), results[n].port());
|
||||
}
|
||||
|
||||
d->nndns_busy = false;
|
||||
d->nndns.stop();
|
||||
|
||||
if(list.isEmpty()) {
|
||||
stop();
|
||||
resultsReady();
|
||||
return;
|
||||
}
|
||||
sortSRVList(list);
|
||||
d->servers = list;
|
||||
|
||||
if(d->srvonly)
|
||||
resultsReady();
|
||||
else {
|
||||
// kick it off
|
||||
d->aaaa = true;
|
||||
tryNext();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// grab the address list and destroy the qdns object
|
||||
QList<QHostAddress> list;
|
||||
if(d->nntype == XMPP::NameRecord::A || d->nntype == XMPP::NameRecord::Aaaa)
|
||||
{
|
||||
for(int n = 0; n < results.count(); ++n)
|
||||
{
|
||||
list += results[n].address();
|
||||
}
|
||||
}
|
||||
d->nndns_busy = false;
|
||||
d->nndns.stop();
|
||||
|
||||
if(!list.isEmpty()) {
|
||||
int port = d->servers.first().port;
|
||||
d->servers.removeFirst();
|
||||
d->aaaa = true;
|
||||
|
||||
d->resultAddress = list.first();
|
||||
d->resultPort = port;
|
||||
resultsReady();
|
||||
}
|
||||
else {
|
||||
if(!d->aaaa)
|
||||
d->servers.removeFirst();
|
||||
d->aaaa = !d->aaaa;
|
||||
|
||||
// failed? bail if last one
|
||||
if(d->servers.isEmpty()) {
|
||||
stop();
|
||||
resultsReady();
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise try the next
|
||||
tryNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SrvResolver::nndns_error(XMPP::NameResolver::Error)
|
||||
{
|
||||
nndns_resultsReady(QList<XMPP::NameRecord>());
|
||||
}
|
||||
|
||||
void SrvResolver::ndns_done()
|
||||
{
|
||||
#ifndef NO_NDNS
|
||||
QHostAddress r = d->ndns.result();
|
||||
int port = d->servers.first().port;
|
||||
d->servers.removeFirst();
|
||||
|
||||
if(!r.isNull()) {
|
||||
d->resultAddress = r;
|
||||
d->resultPort = port;
|
||||
resultsReady();
|
||||
}
|
||||
else {
|
||||
// failed? bail if last one
|
||||
if(d->servers.isEmpty()) {
|
||||
stop();
|
||||
resultsReady();
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise try the next
|
||||
tryNext();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SrvResolver::t_timeout()
|
||||
{
|
||||
stop();
|
||||
resultsReady();
|
||||
}
|
||||
|
||||
// CS_NAMESPACE_END
|
||||
87
iris-legacy/iris/irisnet/legacy/srvresolver.h
Normal file
87
iris-legacy/iris/irisnet/legacy/srvresolver.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* srvresolver.h - class to simplify SRV lookups
|
||||
* Copyright (C) 2003 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CS_SRVRESOLVER_H
|
||||
#define CS_SRVRESOLVER_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include "netnames.h"
|
||||
|
||||
// CS_NAMESPACE_BEGIN
|
||||
|
||||
class INQ3Dns
|
||||
{
|
||||
public:
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
Server(const QString &n = QString(), quint16 p = 0, quint16 w = 0, quint16 po = 0)
|
||||
:name(n), priority(p), weight(w), port(po) {}
|
||||
|
||||
QString name;
|
||||
quint16 priority;
|
||||
quint16 weight;
|
||||
quint16 port;
|
||||
};
|
||||
};
|
||||
|
||||
#define Q3Dns INQ3Dns
|
||||
|
||||
|
||||
class SrvResolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SrvResolver(QObject *parent=0);
|
||||
~SrvResolver();
|
||||
|
||||
void resolve(const QString &server, const QString &type, const QString &proto);
|
||||
void resolveSrvOnly(const QString &server, const QString &type, const QString &proto);
|
||||
void next();
|
||||
void stop();
|
||||
bool isBusy() const;
|
||||
|
||||
QList<Q3Dns::Server> servers() const;
|
||||
|
||||
bool failed() const;
|
||||
QHostAddress resultAddress() const;
|
||||
quint16 resultPort() const;
|
||||
|
||||
signals:
|
||||
void resultsReady();
|
||||
|
||||
private slots:
|
||||
void nndns_resultsReady(const QList<XMPP::NameRecord> &);
|
||||
void nndns_error(XMPP::NameResolver::Error);
|
||||
void ndns_done();
|
||||
void t_timeout();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d;
|
||||
|
||||
void tryNext();
|
||||
void resolve(const QString &server, const QString &type, const QString &proto, bool srvOnly);
|
||||
};
|
||||
|
||||
// CS_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
589
iris-legacy/iris/irisnet/main.cpp
Normal file
589
iris-legacy/iris/irisnet/main.cpp
Normal file
|
|
@ -0,0 +1,589 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "processquit.h"
|
||||
#include "netinterface.h"
|
||||
#include "netnames.h"
|
||||
|
||||
using namespace XMPP;
|
||||
|
||||
class NetMonitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NetInterfaceManager *man;
|
||||
QList<NetInterface*> ifaces;
|
||||
|
||||
~NetMonitor()
|
||||
{
|
||||
qDeleteAll(ifaces);
|
||||
delete man;
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
connect(ProcessQuit::instance(), SIGNAL(quit()), SIGNAL(quit()));
|
||||
|
||||
man = new NetInterfaceManager;
|
||||
connect(man, SIGNAL(interfaceAvailable(const QString &)),
|
||||
SLOT(here(const QString &)));
|
||||
QStringList list = man->interfaces();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
here(list[n]);
|
||||
}
|
||||
|
||||
void here(const QString &id)
|
||||
{
|
||||
NetInterface *iface = new NetInterface(id, man);
|
||||
connect(iface, SIGNAL(unavailable()), SLOT(gone()));
|
||||
printf("HERE: %s name=[%s]\n", qPrintable(iface->id()), qPrintable(iface->name()));
|
||||
QList<QHostAddress> addrs = iface->addresses();
|
||||
for(int n = 0; n < addrs.count(); ++n)
|
||||
printf(" address: %s\n", qPrintable(addrs[n].toString()));
|
||||
if(!iface->gateway().isNull())
|
||||
printf(" gateway: %s\n", qPrintable(iface->gateway().toString()));
|
||||
ifaces += iface;
|
||||
}
|
||||
|
||||
void gone()
|
||||
{
|
||||
NetInterface *iface = (NetInterface *)sender();
|
||||
printf("GONE: %s\n", qPrintable(iface->id()));
|
||||
ifaces.removeAll(iface);
|
||||
delete iface;
|
||||
}
|
||||
};
|
||||
|
||||
static QString dataToString(const QByteArray &buf)
|
||||
{
|
||||
QString out;
|
||||
for(int n = 0; n < buf.size(); ++n)
|
||||
{
|
||||
unsigned char c = (unsigned char)buf[n];
|
||||
if(c == '\\')
|
||||
out += "\\\\";
|
||||
else if(c >= 0x20 || c < 0x7f)
|
||||
out += c;
|
||||
else
|
||||
out += QString("\\x%1").arg((uint)c, 2, 16);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static void print_record(const NameRecord &r)
|
||||
{
|
||||
switch(r.type())
|
||||
{
|
||||
case NameRecord::A:
|
||||
printf("A: [%s] (ttl=%d)\n", qPrintable(r.address().toString()), r.ttl());
|
||||
break;
|
||||
case NameRecord::Aaaa:
|
||||
printf("AAAA: [%s] (ttl=%d)\n", qPrintable(r.address().toString()), r.ttl());
|
||||
break;
|
||||
case NameRecord::Mx:
|
||||
printf("MX: [%s] priority=%d (ttl=%d)\n", r.name().data(), r.priority(), r.ttl());
|
||||
break;
|
||||
case NameRecord::Srv:
|
||||
printf("SRV: [%s] port=%d priority=%d weight=%d (ttl=%d)\n", r.name().data(), r.port(), r.priority(), r.weight(), r.ttl());
|
||||
break;
|
||||
case NameRecord::Ptr:
|
||||
printf("PTR: [%s] (ttl=%d)\n", r.name().data(), r.ttl());
|
||||
break;
|
||||
case NameRecord::Txt:
|
||||
{
|
||||
QList<QByteArray> texts = r.texts();
|
||||
printf("TXT: count=%d (ttl=%d)\n", texts.count(), r.ttl());
|
||||
for(int n = 0; n < texts.count(); ++n)
|
||||
printf(" len=%d [%s]\n", texts[n].size(), qPrintable(dataToString(texts[n])));
|
||||
break;
|
||||
}
|
||||
case NameRecord::Hinfo:
|
||||
printf("HINFO: [%s] [%s] (ttl=%d)\n", r.cpu().data(), r.os().data(), r.ttl());
|
||||
break;
|
||||
case NameRecord::Null:
|
||||
printf("NULL: %d bytes (ttl=%d)\n", r.rawData().size(), r.ttl());
|
||||
break;
|
||||
default:
|
||||
printf("(Unknown): type=%d (ttl=%d)\n", r.type(), r.ttl());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int str2rtype(const QString &in)
|
||||
{
|
||||
QString str = in.toLower();
|
||||
if(str == "a")
|
||||
return NameRecord::A;
|
||||
else if(str == "aaaa")
|
||||
return NameRecord::Aaaa;
|
||||
else if(str == "ptr")
|
||||
return NameRecord::Ptr;
|
||||
else if(str == "srv")
|
||||
return NameRecord::Srv;
|
||||
else if(str == "mx")
|
||||
return NameRecord::Mx;
|
||||
else if(str == "txt")
|
||||
return NameRecord::Txt;
|
||||
else if(str == "hinfo")
|
||||
return NameRecord::Hinfo;
|
||||
else if(str == "null")
|
||||
return NameRecord::Null;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
class ResolveName : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QString name;
|
||||
NameRecord::Type type;
|
||||
bool longlived;
|
||||
NameResolver dns;
|
||||
bool null_dump;
|
||||
|
||||
ResolveName()
|
||||
{
|
||||
null_dump = false;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
connect(ProcessQuit::instance(), SIGNAL(quit()), SIGNAL(quit()));
|
||||
|
||||
connect(&dns, SIGNAL(resultsReady(const QList<XMPP::NameRecord> &)),
|
||||
SLOT(dns_resultsReady(const QList<XMPP::NameRecord> &)));
|
||||
connect(&dns, SIGNAL(error(XMPP::NameResolver::Error)),
|
||||
SLOT(dns_error(XMPP::NameResolver::Error)));
|
||||
|
||||
dns.start(name.toLatin1(), type, longlived ? NameResolver::LongLived : NameResolver::Single);
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void dns_resultsReady(const QList<XMPP::NameRecord> &list)
|
||||
{
|
||||
if(null_dump && list[0].type() == NameRecord::Null)
|
||||
{
|
||||
QByteArray buf = list[0].rawData();
|
||||
fwrite(buf.data(), buf.size(), 1, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
print_record(list[n]);
|
||||
}
|
||||
if(!longlived)
|
||||
{
|
||||
dns.stop();
|
||||
emit quit();
|
||||
}
|
||||
}
|
||||
|
||||
void dns_error(XMPP::NameResolver::Error e)
|
||||
{
|
||||
QString str;
|
||||
if(e == NameResolver::ErrorNoName)
|
||||
str = "ErrorNoName";
|
||||
else if(e == NameResolver::ErrorTimeout)
|
||||
str = "ErrorTimeout";
|
||||
else if(e == NameResolver::ErrorNoLocal)
|
||||
str = "ErrorNoLocal";
|
||||
else if(e == NameResolver::ErrorNoLongLived)
|
||||
str = "ErrorNoLongLived";
|
||||
else // ErrorGeneric, or anything else
|
||||
str = "ErrorGeneric";
|
||||
|
||||
printf("Error: %s\n", qPrintable(str));
|
||||
emit quit();
|
||||
}
|
||||
};
|
||||
|
||||
class BrowseServices : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QString type, domain;
|
||||
ServiceBrowser browser;
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
connect(ProcessQuit::instance(), SIGNAL(quit()), SIGNAL(quit()));
|
||||
|
||||
connect(&browser, SIGNAL(instanceAvailable(const XMPP::ServiceInstance &)),
|
||||
SLOT(browser_instanceAvailable(const XMPP::ServiceInstance &)));
|
||||
connect(&browser, SIGNAL(instanceUnavailable(const XMPP::ServiceInstance &)),
|
||||
SLOT(browser_instanceUnavailable(const XMPP::ServiceInstance &)));
|
||||
connect(&browser, SIGNAL(error()), SLOT(browser_error()));
|
||||
|
||||
browser.start(type, domain);
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void browser_instanceAvailable(const XMPP::ServiceInstance &i)
|
||||
{
|
||||
printf("HERE: [%s] (%d attributes)\n", qPrintable(i.instance()), i.attributes().count());
|
||||
QMap<QString,QByteArray> attribs = i.attributes();
|
||||
QMapIterator<QString,QByteArray> it(attribs);
|
||||
while(it.hasNext())
|
||||
{
|
||||
it.next();
|
||||
printf(" [%s] = [%s]\n", qPrintable(it.key()), qPrintable(dataToString(it.value())));
|
||||
}
|
||||
}
|
||||
|
||||
void browser_instanceUnavailable(const XMPP::ServiceInstance &i)
|
||||
{
|
||||
printf("GONE: [%s]\n", qPrintable(i.instance()));
|
||||
}
|
||||
|
||||
void browser_error()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ResolveService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
int mode;
|
||||
QString instance;
|
||||
QString type;
|
||||
QString domain;
|
||||
int port;
|
||||
|
||||
ServiceResolver dns;
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
connect(ProcessQuit::instance(), SIGNAL(quit()), SIGNAL(quit()));
|
||||
|
||||
connect(&dns, SIGNAL(resultsReady(const QHostAddress &, int)),
|
||||
SLOT(dns_resultsReady(const QHostAddress &, int)));
|
||||
connect(&dns, SIGNAL(finished()), SLOT(dns_finished()));
|
||||
connect(&dns, SIGNAL(error()), SLOT(dns_error()));
|
||||
|
||||
if(mode == 0)
|
||||
dns.startFromInstance(instance.toLatin1() + '.' + type.toLatin1() + ".local.");
|
||||
else if(mode == 1)
|
||||
dns.startFromDomain(domain, type);
|
||||
else // 2
|
||||
dns.startFromPlain(domain, port);
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void dns_resultsReady(const QHostAddress &addr, int port)
|
||||
{
|
||||
printf("[%s] port=%d\n", qPrintable(addr.toString()), port);
|
||||
dns.tryNext();
|
||||
}
|
||||
|
||||
void dns_finished()
|
||||
{
|
||||
emit quit();
|
||||
}
|
||||
|
||||
void dns_error()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class PublishService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QString instance;
|
||||
QString type;
|
||||
int port;
|
||||
QMap<QString,QByteArray> attribs;
|
||||
QByteArray extra_null;
|
||||
|
||||
ServiceLocalPublisher pub;
|
||||
|
||||
public slots:
|
||||
void start()
|
||||
{
|
||||
//NetInterfaceManager::instance();
|
||||
|
||||
connect(ProcessQuit::instance(), SIGNAL(quit()), SIGNAL(quit()));
|
||||
|
||||
connect(&pub, SIGNAL(published()), SLOT(pub_published()));
|
||||
connect(&pub, SIGNAL(error(XMPP::ServiceLocalPublisher::Error)),
|
||||
SLOT(pub_error(XMPP::ServiceLocalPublisher::Error)));
|
||||
|
||||
pub.publish(instance, type, port, attribs);
|
||||
}
|
||||
|
||||
signals:
|
||||
void quit();
|
||||
|
||||
private slots:
|
||||
void pub_published()
|
||||
{
|
||||
printf("Published\n");
|
||||
if(!extra_null.isEmpty())
|
||||
{
|
||||
NameRecord rec;
|
||||
rec.setNull(extra_null);
|
||||
pub.addRecord(rec);
|
||||
}
|
||||
}
|
||||
|
||||
void pub_error(XMPP::ServiceLocalPublisher::Error e)
|
||||
{
|
||||
printf("Error: [%d]\n", e);
|
||||
emit quit();
|
||||
}
|
||||
};
|
||||
|
||||
#include "main.moc"
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("irisnet: simple testing utility\n");
|
||||
printf("usage: irisnet [command]\n");
|
||||
printf("\n");
|
||||
printf(" netmon monitor network interfaces\n");
|
||||
printf(" rname (-r) [domain] (record type) look up record (default = a)\n");
|
||||
printf(" rnamel [domain] [record type] look up record (long-lived)\n");
|
||||
printf(" browse [service type] browse for local services\n");
|
||||
printf(" rservi [instance] [service type] look up browsed instance\n");
|
||||
printf(" rservd [domain] [service type] look up normal SRV\n");
|
||||
printf(" rservp [domain] [port] look up non-SRV\n");
|
||||
printf(" pserv [inst] [type] [port] (attr) (-a [rec]) publish service instance\n");
|
||||
printf("\n");
|
||||
printf("record types: a aaaa ptr srv mx txt hinfo null\n");
|
||||
printf("service types: _service._proto format (e.g. \"_xmpp-client._tcp\")\n");
|
||||
printf("attributes: var0[=val0],...,varn[=valn]\n");
|
||||
printf("rname -r: for null type, dump raw record data to stdout\n");
|
||||
printf("pub -a: add extra record. format: null:filename.dat\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
if(argc < 2)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QStringList args;
|
||||
for(int n = 1; n < argc; ++n)
|
||||
args += argv[n];
|
||||
|
||||
if(args[0] == "netmon")
|
||||
{
|
||||
NetMonitor a;
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
}
|
||||
else if(args[0] == "rname" || args[0] == "rnamel")
|
||||
{
|
||||
bool null_dump = false;
|
||||
for(int n = 1; n < args.count(); ++n)
|
||||
{
|
||||
if(args[n] == "-r")
|
||||
{
|
||||
null_dump = true;
|
||||
args.removeAt(n);
|
||||
--n;
|
||||
}
|
||||
}
|
||||
|
||||
if(args.count() < 2)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
if(args[0] == "rnamel" && args.count() < 3)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
int x = NameRecord::A;
|
||||
if(args.count() >= 3)
|
||||
{
|
||||
x = str2rtype(args[2]);
|
||||
if(x == -1)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
ResolveName a;
|
||||
a.name = args[1];
|
||||
a.type = (NameRecord::Type)x;
|
||||
a.longlived = (args[0] == "rnamel") ? true : false;
|
||||
if(args[0] == "rname" && null_dump)
|
||||
a.null_dump = true;
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
}
|
||||
else if(args[0] == "browse")
|
||||
{
|
||||
if(args.count() < 2)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
BrowseServices a;
|
||||
a.type = args[1];
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
}
|
||||
else if(args[0] == "rservi" || args[0] == "rservd" || args[0] == "rservp")
|
||||
{
|
||||
// they all take 2 params
|
||||
if(args.count() < 3)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ResolveService a;
|
||||
if(args[0] == "rservi")
|
||||
{
|
||||
a.mode = 0;
|
||||
a.instance = args[1];
|
||||
a.type = args[2];
|
||||
}
|
||||
else if(args[0] == "rservd")
|
||||
{
|
||||
a.mode = 1;
|
||||
a.domain = args[1];
|
||||
a.type = args[2];
|
||||
}
|
||||
else // rservp
|
||||
{
|
||||
a.mode = 2;
|
||||
a.domain = args[1];
|
||||
a.port = args[2].toInt();
|
||||
}
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
}
|
||||
else if(args[0] == "pserv")
|
||||
{
|
||||
QStringList addrecs;
|
||||
for(int n = 1; n < args.count(); ++n)
|
||||
{
|
||||
if(args[n] == "-a")
|
||||
{
|
||||
if(n + 1 < args.count())
|
||||
{
|
||||
addrecs += args[n + 1];
|
||||
args.removeAt(n);
|
||||
args.removeAt(n);
|
||||
--n;
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray extra_null;
|
||||
for(int n = 0; n < addrecs.count(); ++n)
|
||||
{
|
||||
const QString &str = addrecs[n];
|
||||
int x = str.indexOf(':');
|
||||
if(x == -1 || str.mid(0, x) != "null")
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QString null_file = str.mid(x + 1);
|
||||
|
||||
if(!null_file.isEmpty())
|
||||
{
|
||||
QFile f(null_file);
|
||||
if(!f.open(QFile::ReadOnly))
|
||||
{
|
||||
printf("can't read file\n");
|
||||
return 1;
|
||||
}
|
||||
extra_null = f.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
if(args.count() < 4)
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
QMap<QString,QByteArray> attribs;
|
||||
if(args.count() > 4)
|
||||
{
|
||||
QStringList parts = args[4].split(',');
|
||||
for(int n = 0; n < parts.count(); ++n)
|
||||
{
|
||||
const QString &str = parts[n];
|
||||
int x = str.indexOf('=');
|
||||
if(x != -1)
|
||||
attribs.insert(str.mid(0, x), str.mid(x + 1).toUtf8());
|
||||
else
|
||||
attribs.insert(str, QByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
PublishService a;
|
||||
a.instance = args[1];
|
||||
a.type = args[2];
|
||||
a.port = args[3].toInt();
|
||||
a.attribs = attribs;
|
||||
a.extra_null = extra_null;
|
||||
QObject::connect(&a, SIGNAL(quit()), &app, SLOT(quit()));
|
||||
QTimer::singleShot(0, &a, SLOT(start()));
|
||||
app.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
498
iris-legacy/iris/irisnet/netinterface.cpp
Normal file
498
iris-legacy/iris/irisnet/netinterface.cpp
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "netinterface.h"
|
||||
|
||||
#include "irisnetplugin.h"
|
||||
#include "irisnetglobal_p.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NetTracker
|
||||
//----------------------------------------------------------------------------
|
||||
class NetTracker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static NetTracker *self;
|
||||
|
||||
NetInterfaceProvider *c;
|
||||
QList<NetInterfaceProvider::Info> info;
|
||||
QMutex m;
|
||||
|
||||
NetTracker()
|
||||
{
|
||||
self = this;
|
||||
QList<IrisNetProvider*> list = irisNetProviders();
|
||||
c = 0;
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
IrisNetProvider *p = list[n];
|
||||
c = p->createNetInterfaceProvider();
|
||||
if(c)
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(c); // we have built-in support, so this should never fail
|
||||
connect(c, SIGNAL(updated()), SLOT(c_updated()));
|
||||
}
|
||||
|
||||
~NetTracker()
|
||||
{
|
||||
delete c;
|
||||
self = 0;
|
||||
}
|
||||
|
||||
static NetTracker *instance()
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
c->start();
|
||||
info = filterList(c->interfaces());
|
||||
}
|
||||
|
||||
QList<NetInterfaceProvider::Info> getInterfaces()
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
return info;
|
||||
}
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
|
||||
public slots:
|
||||
void c_updated()
|
||||
{
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
info = filterList(c->interfaces());
|
||||
}
|
||||
emit updated();
|
||||
}
|
||||
|
||||
private:
|
||||
static QList<NetInterfaceProvider::Info> filterList(const QList<NetInterfaceProvider::Info> &in)
|
||||
{
|
||||
QList<NetInterfaceProvider::Info> out;
|
||||
for(int n = 0; n < in.count(); ++n)
|
||||
{
|
||||
if(!in[n].isLoopback)
|
||||
out += in[n];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
NetTracker *NetTracker::self = 0;
|
||||
|
||||
class SyncThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QMutex control_mutex;
|
||||
QWaitCondition control_wait;
|
||||
QEventLoop *loop;
|
||||
|
||||
SyncThread(QObject *parent = 0) : QThread(parent)
|
||||
{
|
||||
loop = 0;
|
||||
}
|
||||
|
||||
~SyncThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
control_mutex.lock();
|
||||
QThread::start();
|
||||
control_wait.wait(&control_mutex);
|
||||
control_mutex.unlock();
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
{
|
||||
QMutexLocker locker(&control_mutex);
|
||||
if(loop)
|
||||
QMetaObject::invokeMethod(loop, "quit");
|
||||
}
|
||||
wait();
|
||||
}
|
||||
|
||||
virtual void run()
|
||||
{
|
||||
control_mutex.lock();
|
||||
loop = new QEventLoop;
|
||||
begin();
|
||||
control_wait.wakeOne();
|
||||
control_mutex.unlock();
|
||||
loop->exec();
|
||||
QMutexLocker locker(&control_mutex);
|
||||
end();
|
||||
delete loop;
|
||||
loop = 0;
|
||||
}
|
||||
|
||||
virtual void begin()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void end()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class NetThread : public SyncThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NetTracker *tracker;
|
||||
|
||||
NetThread(QObject *parent = 0) : SyncThread(parent)
|
||||
{
|
||||
}
|
||||
|
||||
~NetThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
virtual void begin()
|
||||
{
|
||||
tracker = new NetTracker;
|
||||
tracker->start();
|
||||
}
|
||||
|
||||
virtual void end()
|
||||
{
|
||||
delete tracker;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NetInterface
|
||||
//----------------------------------------------------------------------------
|
||||
class NetInterfacePrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
friend class NetInterfaceManagerPrivate;
|
||||
|
||||
NetInterface *q;
|
||||
|
||||
NetInterfaceManager *man;
|
||||
bool valid;
|
||||
QString id, name;
|
||||
QList<QHostAddress> addrs;
|
||||
QHostAddress gw;
|
||||
|
||||
NetInterfacePrivate(NetInterface *_q) : QObject(_q), q(_q)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
|
||||
void doUnavailable()
|
||||
{
|
||||
man->unreg(q);
|
||||
valid = false;
|
||||
emit q->unavailable();
|
||||
}
|
||||
};
|
||||
|
||||
NetInterface::NetInterface(const QString &id, NetInterfaceManager *manager)
|
||||
:QObject(manager)
|
||||
{
|
||||
d = new NetInterfacePrivate(this);
|
||||
d->man = manager;
|
||||
|
||||
NetInterfaceProvider::Info *info = (NetInterfaceProvider::Info *)d->man->reg(id, this);
|
||||
if(info)
|
||||
{
|
||||
d->valid = true;
|
||||
d->id = info->id;
|
||||
d->name = info->name;
|
||||
d->addrs = info->addresses;
|
||||
d->gw = info->gateway;
|
||||
delete info;
|
||||
}
|
||||
}
|
||||
|
||||
NetInterface::~NetInterface()
|
||||
{
|
||||
d->man->unreg(this);
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool NetInterface::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
||||
|
||||
QString NetInterface::id() const
|
||||
{
|
||||
return d->id;
|
||||
}
|
||||
|
||||
QString NetInterface::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
QList<QHostAddress> NetInterface::addresses() const
|
||||
{
|
||||
return d->addrs;
|
||||
}
|
||||
|
||||
QHostAddress NetInterface::gateway() const
|
||||
{
|
||||
return d->gw;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NetInterfaceManager
|
||||
//----------------------------------------------------------------------------
|
||||
class NetInterfaceManagerGlobal;
|
||||
|
||||
Q_GLOBAL_STATIC(QMutex, nim_mutex)
|
||||
static NetInterfaceManagerGlobal *g_nim = 0;
|
||||
|
||||
class NetInterfaceManagerGlobal
|
||||
{
|
||||
public:
|
||||
NetThread *thread;
|
||||
int refs;
|
||||
|
||||
NetInterfaceManagerGlobal()
|
||||
{
|
||||
thread = 0;
|
||||
refs = 0;
|
||||
}
|
||||
|
||||
~NetInterfaceManagerGlobal()
|
||||
{
|
||||
}
|
||||
|
||||
// global mutex must be locked while calling this
|
||||
void addRef()
|
||||
{
|
||||
if(refs == 0)
|
||||
{
|
||||
thread = new NetThread;
|
||||
thread->moveToThread(QCoreApplication::instance()->thread());
|
||||
thread->start();
|
||||
}
|
||||
++refs;
|
||||
}
|
||||
|
||||
// global mutex must be locked while calling this
|
||||
void removeRef()
|
||||
{
|
||||
Q_ASSERT(refs > 0);
|
||||
--refs;
|
||||
if(refs == 0)
|
||||
{
|
||||
delete thread;
|
||||
thread = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class NetInterfaceManagerPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NetInterfaceManager *q;
|
||||
|
||||
QMutex m;
|
||||
QList<NetInterfaceProvider::Info> info;
|
||||
QList<NetInterface*> listeners;
|
||||
bool pending;
|
||||
|
||||
NetInterfaceManagerPrivate(NetInterfaceManager *_q) : q(_q)
|
||||
{
|
||||
pending = false;
|
||||
}
|
||||
|
||||
static int lookup(const QList<NetInterfaceProvider::Info> &list, const QString &id)
|
||||
{
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
if(list[n].id == id)
|
||||
return n;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool sameContent(const NetInterfaceProvider::Info &a, const NetInterfaceProvider::Info &b)
|
||||
{
|
||||
// assume ids are the same already
|
||||
if(a.name == b.name && a.isLoopback == b.isLoopback && a.addresses == b.addresses && a.gateway == b.gateway)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void do_update()
|
||||
{
|
||||
// grab the latest info
|
||||
QList<NetInterfaceProvider::Info> newinfo = NetTracker::instance()->getInterfaces();
|
||||
|
||||
QStringList here_ids, gone_ids;
|
||||
|
||||
// removed / changed
|
||||
for(int n = 0; n < info.count(); ++n)
|
||||
{
|
||||
int i = lookup(newinfo, info[n].id);
|
||||
// id is still here
|
||||
if(i != -1)
|
||||
{
|
||||
// content changed?
|
||||
if(!sameContent(info[n], newinfo[i]))
|
||||
{
|
||||
gone_ids += info[n].id;
|
||||
here_ids += info[n].id;
|
||||
}
|
||||
}
|
||||
// id is gone
|
||||
else
|
||||
gone_ids += info[n].id;
|
||||
}
|
||||
|
||||
// added
|
||||
for(int n = 0; n < newinfo.count(); ++n)
|
||||
{
|
||||
int i = lookup(info, newinfo[n].id);
|
||||
if(i == -1)
|
||||
here_ids += newinfo[n].id;
|
||||
}
|
||||
info = newinfo;
|
||||
|
||||
// announce gone
|
||||
for(int n = 0; n < gone_ids.count(); ++n)
|
||||
{
|
||||
// work on a copy, just in case the list changes.
|
||||
// it is important to make the copy here, and not
|
||||
// outside the outer loop, in case the items
|
||||
// get deleted
|
||||
QList<NetInterface*> list = listeners;
|
||||
for(int i = 0; i < list.count(); ++i)
|
||||
{
|
||||
if(list[i]->d->id == gone_ids[n])
|
||||
list[i]->d->doUnavailable();
|
||||
}
|
||||
}
|
||||
|
||||
// announce here
|
||||
for(int n = 0; n < here_ids.count(); ++n)
|
||||
emit q->interfaceAvailable(here_ids[n]);
|
||||
}
|
||||
|
||||
public slots:
|
||||
void tracker_updated()
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
if(!pending)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
void update()
|
||||
{
|
||||
m.lock();
|
||||
pending = false;
|
||||
m.unlock();
|
||||
|
||||
do_update();
|
||||
}
|
||||
};
|
||||
|
||||
NetInterfaceManager::NetInterfaceManager(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
QMutexLocker locker(nim_mutex());
|
||||
if(!g_nim)
|
||||
g_nim = new NetInterfaceManagerGlobal;
|
||||
|
||||
d = new NetInterfaceManagerPrivate(this);
|
||||
g_nim->addRef();
|
||||
d->connect(NetTracker::instance(), SIGNAL(updated()), SLOT(tracker_updated()), Qt::DirectConnection);
|
||||
}
|
||||
|
||||
NetInterfaceManager::~NetInterfaceManager()
|
||||
{
|
||||
QMutexLocker locker(nim_mutex());
|
||||
g_nim->removeRef();
|
||||
delete d;
|
||||
if(g_nim->refs == 0)
|
||||
{
|
||||
delete g_nim;
|
||||
g_nim = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList NetInterfaceManager::interfaces() const
|
||||
{
|
||||
d->info = NetTracker::instance()->getInterfaces();
|
||||
QStringList out;
|
||||
for(int n = 0; n < d->info.count(); ++n)
|
||||
out += d->info[n].id;
|
||||
return out;
|
||||
}
|
||||
|
||||
QString NetInterfaceManager::interfaceForAddress(const QHostAddress &a)
|
||||
{
|
||||
NetInterfaceManager netman;
|
||||
QStringList list = netman.interfaces();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
NetInterface iface(list[n], &netman);
|
||||
if(iface.addresses().contains(a))
|
||||
return list[n];
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void *NetInterfaceManager::reg(const QString &id, NetInterface *i)
|
||||
{
|
||||
for(int n = 0; n < d->info.count(); ++n)
|
||||
{
|
||||
if(d->info[n].id == id)
|
||||
{
|
||||
d->listeners += i;
|
||||
return new NetInterfaceProvider::Info(d->info[n]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetInterfaceManager::unreg(NetInterface *i)
|
||||
{
|
||||
d->listeners.removeAll(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "netinterface.moc"
|
||||
211
iris-legacy/iris/irisnet/netinterface.h
Normal file
211
iris-legacy/iris/irisnet/netinterface.h
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NETINTERFACE_H
|
||||
#define NETINTERFACE_H
|
||||
|
||||
#include "irisnetglobal.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
class NetInterfaceManager;
|
||||
class NetInterfacePrivate;
|
||||
class NetInterfaceManagerPrivate;
|
||||
|
||||
/**
|
||||
\brief Provides information about a network interface
|
||||
|
||||
NetInterface provides information about a particular network interface. Construct it by passing the interface id of interest (e.g. "eth0") and a NetInterfaceManager parent object. Interface ids can be obtained from NetInterfaceManager.
|
||||
|
||||
To test if a NetInterface is valid, call isValid(). Use name() to return a display-friendly name of the interface. The addresses() function returns a list of IP addresses for this interface. There may be a gateway IP address associated with this interface, which can be fetched with gateway().
|
||||
|
||||
Here's an example of how to print the IP addresses of eth0:
|
||||
\code
|
||||
NetInterface iface("eth0");
|
||||
if(iface.isValid())
|
||||
{
|
||||
QList<QHostAddress> addrs = iface.addresses();
|
||||
for(int n = 0; n < addrs.count(); ++n)
|
||||
printf("%s\n", qPrintable(addrs[n].toString()));
|
||||
}
|
||||
\endcode
|
||||
|
||||
If the interface goes away, the unavailable() signal is emitted and the NetInterface becomes invalid.
|
||||
|
||||
\sa NetInterfaceManager
|
||||
*/
|
||||
class IRISNET_EXPORT NetInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief Constructs a new interface object with the given \a id and \a manager
|
||||
|
||||
If \a id is not a valid interface id, then the object will not be valid (isValid() will return false). Normally it is not necessary to check for validity, since interface ids obtained from NetInterfaceManager are guaranteed to be valid until the event loop resumes.
|
||||
|
||||
\sa isValid
|
||||
*/
|
||||
NetInterface(const QString &id, NetInterfaceManager *manager);
|
||||
|
||||
/**
|
||||
\brief Destroys the interface object
|
||||
*/
|
||||
~NetInterface();
|
||||
|
||||
/**
|
||||
\brief Returns true if the interface is valid, otherwise returns false
|
||||
|
||||
\sa unavailable
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
\brief Returns the id of this interface
|
||||
|
||||
This is the id that was passed in the constructor.
|
||||
*/
|
||||
QString id() const;
|
||||
|
||||
/**
|
||||
\brief Returns a display-friendly name of this interface
|
||||
|
||||
The name may be the same as the id.
|
||||
|
||||
\sa id
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
\brief Returns the addresses of this interface
|
||||
|
||||
There will always be at least one address. In some cases there might be multiple, such as on Unix where it is possible for the same interface to have both an IPv4 and an IPv6 address.
|
||||
*/
|
||||
QList<QHostAddress> addresses() const;
|
||||
|
||||
/**
|
||||
\brief Returns the gateway of this interface
|
||||
|
||||
If there is no gateway associated with this interface, a null QHostAddress is returned.
|
||||
*/
|
||||
QHostAddress gateway() const; // optional
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Notifies when the interface becomes unavailable
|
||||
|
||||
Once this signal is emitted, the NetInterface object becomes invalid and is no longer very useful. A new NetInterface object must be created if a valid object with current information is desired.
|
||||
|
||||
\note If the interface information changes, the interface is considered to have become unavailable.
|
||||
|
||||
\sa isValid
|
||||
*/
|
||||
void unavailable();
|
||||
|
||||
private:
|
||||
friend class NetInterfacePrivate;
|
||||
NetInterfacePrivate *d;
|
||||
|
||||
friend class NetInterfaceManagerPrivate;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Manages network interface information
|
||||
|
||||
NetInterfaceManager keeps track of all available network interfaces.
|
||||
|
||||
An interface is considered available if it exists, is "Up", has at least one IP address, and is non-Loopback.
|
||||
|
||||
The interfaces() function returns a list of available interface ids. These ids can be used with NetInterface to get information about the interfaces. For example, here is how you could print the names of the available interfaces:
|
||||
|
||||
\code
|
||||
NetInterfaceManager netman;
|
||||
QStringList id_list = netman.interfaces();
|
||||
for(int n = 0; n < id_list.count(); ++n)
|
||||
{
|
||||
NetInterface iface(id_list[n], &netman);
|
||||
printf("name: [%s]\n", qPrintable(iface.name()));
|
||||
}
|
||||
\endcode
|
||||
|
||||
When a new network interface is available, the interfaceAvailable() signal will emitted. Note that interface unavailability is not notified by NetInterfaceManager. Instead, use NetInterface to monitor a specific network interface for unavailability.
|
||||
|
||||
Interface ids obtained through NetInterfaceManager are guaranteed to be valid until the event loop resumes, or until the next call to interfaces() or interfaceForAddress().
|
||||
|
||||
\sa NetInterface
|
||||
*/
|
||||
class IRISNET_EXPORT NetInterfaceManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief Constructs a new manager object with the given \a parent
|
||||
*/
|
||||
NetInterfaceManager(QObject *parent = 0);
|
||||
|
||||
/**
|
||||
\brief Destroys the manager object
|
||||
*/
|
||||
~NetInterfaceManager();
|
||||
|
||||
/**
|
||||
\brief Returns the list of available interface ids
|
||||
|
||||
\sa interfaceAvailable
|
||||
\sa interfaceForAddress
|
||||
*/
|
||||
QStringList interfaces() const;
|
||||
|
||||
/**
|
||||
\brief Looks up an interface id by IP address
|
||||
|
||||
This function looks for an interface that has the address \a a. If there is no such interface, a null string is returned.
|
||||
|
||||
This is useful for determing the network interface associated with an outgoing QTcpSocket:
|
||||
|
||||
\code
|
||||
QString iface = NetInterfaceManager::interfaceForAddress(tcpSocket->localAddress());
|
||||
\endcode
|
||||
|
||||
\sa interfaces
|
||||
*/
|
||||
static QString interfaceForAddress(const QHostAddress &a);
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Notifies when an interface becomes available
|
||||
|
||||
The \a id parameter is the interface id, ready to use with NetInterface.
|
||||
*/
|
||||
void interfaceAvailable(const QString &id);
|
||||
|
||||
private:
|
||||
friend class NetInterfaceManagerPrivate;
|
||||
NetInterfaceManagerPrivate *d;
|
||||
|
||||
friend class NetInterface;
|
||||
friend class NetInterfacePrivate;
|
||||
|
||||
void *reg(const QString &id, NetInterface *i);
|
||||
void unreg(NetInterface *i);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
425
iris-legacy/iris/irisnet/netinterface_unix.cpp
Normal file
425
iris-legacy/iris/irisnet/netinterface_unix.cpp
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
// this code assumes the following ioctls work:
|
||||
// SIOCGIFCONF - get list of devices
|
||||
// SIOCGIFFLAGS - get flags about a device
|
||||
|
||||
// gateway detection currently only works on linux
|
||||
|
||||
#include "irisnetplugin.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
// for solaris
|
||||
#ifndef SIOCGIFCONF
|
||||
# include<sys/sockio.h>
|
||||
#endif
|
||||
|
||||
class UnixIface
|
||||
{
|
||||
public:
|
||||
QString name;
|
||||
bool loopback;
|
||||
QHostAddress address;
|
||||
};
|
||||
|
||||
class UnixGateway
|
||||
{
|
||||
public:
|
||||
QString ifaceName;
|
||||
QHostAddress address;
|
||||
};
|
||||
|
||||
static QList<UnixIface> get_sioc_ifaces()
|
||||
{
|
||||
QList<UnixIface> out;
|
||||
|
||||
int tmpsock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(tmpsock < 0)
|
||||
return out;
|
||||
|
||||
struct ifconf ifc;
|
||||
int lastlen = 0;
|
||||
QByteArray buf(100 * sizeof(struct ifreq), 0); // guess
|
||||
while(1)
|
||||
{
|
||||
ifc.ifc_len = buf.size();
|
||||
ifc.ifc_buf = buf.data();
|
||||
if(ioctl(tmpsock, SIOCGIFCONF, &ifc) < 0)
|
||||
{
|
||||
if(errno != EINVAL || lastlen != 0)
|
||||
return out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if it didn't grow since last time, then
|
||||
// there's no overflow
|
||||
if(ifc.ifc_len == lastlen)
|
||||
break;
|
||||
lastlen = ifc.ifc_len;
|
||||
}
|
||||
buf.resize(buf.size() + 10 * sizeof(struct ifreq));
|
||||
}
|
||||
buf.resize(lastlen);
|
||||
|
||||
int itemsize;
|
||||
for(int at = 0; at < buf.size(); at += itemsize)
|
||||
{
|
||||
struct ifreq *ifr = (struct ifreq *)(buf.data() + at);
|
||||
|
||||
int sockaddr_len;
|
||||
if(((struct sockaddr *)&ifr->ifr_addr)->sa_family == AF_INET)
|
||||
sockaddr_len = sizeof(struct sockaddr_in);
|
||||
else if(((struct sockaddr *)&ifr->ifr_addr)->sa_family == AF_INET6)
|
||||
sockaddr_len = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
sockaddr_len = sizeof(struct sockaddr);
|
||||
|
||||
// set this asap so the next iteration is possible
|
||||
itemsize = sizeof(ifr->ifr_name) + sockaddr_len;
|
||||
|
||||
// skip if the family is 0 (sometimes you get empty entries)
|
||||
if(ifr->ifr_addr.sa_family == 0)
|
||||
continue;
|
||||
|
||||
// make a copy of this item to do additional ioctls on
|
||||
struct ifreq ifrcopy = *ifr;
|
||||
|
||||
// grab the flags
|
||||
if(ioctl(tmpsock, SIOCGIFFLAGS, &ifrcopy) < 0)
|
||||
continue;
|
||||
|
||||
// device must be up and not loopback
|
||||
if(!(ifrcopy.ifr_flags & IFF_UP))
|
||||
continue;
|
||||
|
||||
UnixIface i;
|
||||
i.name = QString::fromLatin1(ifr->ifr_name);
|
||||
i.loopback = (ifrcopy.ifr_flags & IFF_LOOPBACK) ? true : false;
|
||||
i.address.setAddress(&ifr->ifr_addr);
|
||||
out += i;
|
||||
}
|
||||
|
||||
// don't need this anymore
|
||||
close(tmpsock);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static QStringList read_proc_as_lines(const char *procfile)
|
||||
{
|
||||
QStringList out;
|
||||
|
||||
FILE *f = fopen(procfile, "r");
|
||||
if(!f)
|
||||
return out;
|
||||
|
||||
QByteArray buf;
|
||||
while(!feof(f))
|
||||
{
|
||||
// max read on a proc is 4K
|
||||
QByteArray block(4096, 0);
|
||||
int ret = fread(block.data(), 1, block.size(), f);
|
||||
if(ret <= 0)
|
||||
break;
|
||||
block.resize(ret);
|
||||
buf += block;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
QString str = QString::fromLocal8Bit(buf);
|
||||
out = str.split('\n', QString::SkipEmptyParts);
|
||||
return out;
|
||||
}
|
||||
|
||||
static QHostAddress linux_ipv6_to_qaddr(const QString &in)
|
||||
{
|
||||
QHostAddress out;
|
||||
if(in.length() != 32)
|
||||
return out;
|
||||
quint8 raw[16];
|
||||
for(int n = 0; n < 16; ++n)
|
||||
{
|
||||
bool ok;
|
||||
int x = in.mid(n * 2, 2).toInt(&ok, 16);
|
||||
if(!ok)
|
||||
return out;
|
||||
raw[n] = (quint8)x;
|
||||
}
|
||||
out.setAddress(raw);
|
||||
return out;
|
||||
}
|
||||
|
||||
static QHostAddress linux_ipv4_to_qaddr(const QString &in)
|
||||
{
|
||||
QHostAddress out;
|
||||
if(in.length() != 8)
|
||||
return out;
|
||||
quint32 raw;
|
||||
unsigned char *rawp = (unsigned char *)&raw;
|
||||
for(int n = 0; n < 4; ++n)
|
||||
{
|
||||
bool ok;
|
||||
int x = in.mid(n * 2, 2).toInt(&ok, 16);
|
||||
if(!ok)
|
||||
return out;
|
||||
rawp[n] = (unsigned char )x;
|
||||
}
|
||||
out.setAddress(raw);
|
||||
return out;
|
||||
}
|
||||
|
||||
static QList<UnixIface> get_linux_ipv6_ifaces()
|
||||
{
|
||||
QList<UnixIface> out;
|
||||
|
||||
QStringList lines = read_proc_as_lines("/proc/net/if_inet6");
|
||||
for(int n = 0; n < lines.count(); ++n)
|
||||
{
|
||||
const QString &line = lines[n];
|
||||
QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts);
|
||||
if(parts.count() < 6)
|
||||
continue;
|
||||
|
||||
QString name = parts[5];
|
||||
if(name.isEmpty())
|
||||
continue;
|
||||
QHostAddress addr = linux_ipv6_to_qaddr(parts[0]);
|
||||
if(addr.isNull())
|
||||
continue;
|
||||
|
||||
QString scopestr = parts[3];
|
||||
bool ok;
|
||||
unsigned int scope = parts[3].toInt(&ok, 16);
|
||||
if(!ok)
|
||||
continue;
|
||||
|
||||
// IPV6_ADDR_LOOPBACK 0x0010U
|
||||
// IPV6_ADDR_SCOPE_MASK 0x00f0U
|
||||
bool loopback = false;
|
||||
if((scope & 0x00f0U) == 0x0010U)
|
||||
loopback = true;
|
||||
|
||||
UnixIface i;
|
||||
i.name = name;
|
||||
i.loopback = loopback;
|
||||
i.address = addr;
|
||||
out += i;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static QList<UnixGateway> get_linux_gateways()
|
||||
{
|
||||
QList<UnixGateway> out;
|
||||
|
||||
QStringList lines = read_proc_as_lines("/proc/net/route");
|
||||
// skip the first line, so we start at 1
|
||||
for(int n = 1; n < lines.count(); ++n)
|
||||
{
|
||||
const QString &line = lines[n];
|
||||
QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts);
|
||||
if(parts.count() < 10) // net-tools does 10, but why not 11?
|
||||
continue;
|
||||
|
||||
QHostAddress addr = linux_ipv4_to_qaddr(parts[2]);
|
||||
if(addr.isNull())
|
||||
continue;
|
||||
|
||||
int iflags = parts[3].toInt(0, 16);
|
||||
if(!(iflags & RTF_UP))
|
||||
continue;
|
||||
|
||||
if(!(iflags & RTF_GATEWAY))
|
||||
continue;
|
||||
|
||||
UnixGateway g;
|
||||
g.ifaceName = parts[0];
|
||||
g.address = addr;
|
||||
out += g;
|
||||
}
|
||||
|
||||
lines = read_proc_as_lines("/proc/net/ipv6_route");
|
||||
for(int n = 0; n < lines.count(); ++n)
|
||||
{
|
||||
const QString &line = lines[n];
|
||||
QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts);
|
||||
if(parts.count() < 10)
|
||||
continue;
|
||||
|
||||
QHostAddress addr = linux_ipv6_to_qaddr(parts[4]);
|
||||
if(addr.isNull())
|
||||
continue;
|
||||
|
||||
int iflags = parts[8].toInt(0, 16);
|
||||
if(!(iflags & RTF_UP))
|
||||
continue;
|
||||
|
||||
if(!(iflags & RTF_GATEWAY))
|
||||
continue;
|
||||
|
||||
UnixGateway g;
|
||||
g.ifaceName = parts[9];
|
||||
g.address = addr;
|
||||
out += g;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static QList<UnixIface> get_unix_ifaces()
|
||||
{
|
||||
QList<UnixIface> out = get_sioc_ifaces();
|
||||
#ifdef Q_OS_LINUX
|
||||
out += get_linux_ipv6_ifaces();
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
static QList<UnixGateway> get_unix_gateways()
|
||||
{
|
||||
// support other platforms here
|
||||
QList<UnixGateway> out;
|
||||
#ifdef Q_OS_LINUX
|
||||
out = get_linux_gateways();
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
class UnixNet : public NetInterfaceProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(XMPP::NetInterfaceProvider);
|
||||
public:
|
||||
QList<Info> info;
|
||||
QTimer t;
|
||||
|
||||
UnixNet() : t(this)
|
||||
{
|
||||
connect(&t, SIGNAL(timeout()), SLOT(check()));
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
t.start(5000);
|
||||
poll();
|
||||
}
|
||||
|
||||
QList<Info> interfaces() const
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
void poll()
|
||||
{
|
||||
QList<Info> ifaces;
|
||||
|
||||
QList<UnixIface> list = get_unix_ifaces();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
// see if we have it already
|
||||
int lookup = -1;
|
||||
for(int k = 0; k < ifaces.count(); ++k)
|
||||
{
|
||||
if(ifaces[k].id == list[n].name)
|
||||
{
|
||||
lookup = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// don't have it? make it
|
||||
if(lookup == -1)
|
||||
{
|
||||
Info i;
|
||||
i.id = list[n].name;
|
||||
i.name = list[n].name;
|
||||
i.isLoopback = list[n].loopback;
|
||||
i.addresses += list[n].address;
|
||||
ifaces += i;
|
||||
}
|
||||
// otherwise, tack on the address
|
||||
else
|
||||
ifaces[lookup].addresses += list[n].address;
|
||||
}
|
||||
|
||||
QList<UnixGateway> glist = get_unix_gateways();
|
||||
for(int n = 0; n < glist.count(); ++n)
|
||||
{
|
||||
// look up the interface
|
||||
int lookup = -1;
|
||||
for(int k = 0; k < ifaces.count(); ++k)
|
||||
{
|
||||
if(ifaces[k].id == glist[n].ifaceName)
|
||||
{
|
||||
lookup = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(lookup == -1)
|
||||
break;
|
||||
|
||||
ifaces[lookup].gateway = glist[n].address;
|
||||
}
|
||||
|
||||
info = ifaces;
|
||||
}
|
||||
|
||||
signals:
|
||||
void updated();
|
||||
|
||||
public slots:
|
||||
void check()
|
||||
{
|
||||
poll();
|
||||
emit updated();
|
||||
}
|
||||
};
|
||||
|
||||
class UnixNetProvider : public IrisNetProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(XMPP::IrisNetProvider);
|
||||
public:
|
||||
virtual NetInterfaceProvider *createNetInterfaceProvider()
|
||||
{
|
||||
return new UnixNet;
|
||||
}
|
||||
};
|
||||
|
||||
IrisNetProvider *irisnet_createUnixNetProvider()
|
||||
{
|
||||
return new UnixNetProvider;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "netinterface_unix.moc"
|
||||
960
iris-legacy/iris/irisnet/netnames.cpp
Normal file
960
iris-legacy/iris/irisnet/netnames.cpp
Normal file
|
|
@ -0,0 +1,960 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "netnames.h"
|
||||
|
||||
#include <idna.h>
|
||||
#include "irisnetplugin.h"
|
||||
#include "irisnetglobal_p.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NameRecord
|
||||
//----------------------------------------------------------------------------
|
||||
class NameRecord::Private : public QSharedData
|
||||
{
|
||||
public:
|
||||
QByteArray owner;
|
||||
NameRecord::Type type;
|
||||
int ttl;
|
||||
|
||||
QHostAddress address;
|
||||
QByteArray name;
|
||||
int priority, weight, port;
|
||||
QList<QByteArray> texts;
|
||||
QByteArray cpu, os;
|
||||
QByteArray rawData;
|
||||
};
|
||||
|
||||
#define ENSURE_D { if(!d) d = new Private; }
|
||||
|
||||
NameRecord::NameRecord()
|
||||
{
|
||||
d = 0;
|
||||
}
|
||||
|
||||
NameRecord::NameRecord(const QByteArray &owner, int ttl)
|
||||
{
|
||||
d = 0;
|
||||
setOwner(owner);
|
||||
setTTL(ttl);
|
||||
}
|
||||
|
||||
NameRecord::NameRecord(const NameRecord &from)
|
||||
{
|
||||
d = 0;
|
||||
*this = from;
|
||||
}
|
||||
|
||||
NameRecord::~NameRecord()
|
||||
{
|
||||
}
|
||||
|
||||
NameRecord & NameRecord::operator=(const NameRecord &from)
|
||||
{
|
||||
d = from.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool NameRecord::isNull() const
|
||||
{
|
||||
return (d ? false : true);
|
||||
}
|
||||
|
||||
QByteArray NameRecord::owner() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
int NameRecord::ttl() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->ttl;
|
||||
}
|
||||
|
||||
NameRecord::Type NameRecord::type() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->type;
|
||||
}
|
||||
|
||||
QHostAddress NameRecord::address() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->address;
|
||||
}
|
||||
|
||||
QByteArray NameRecord::name() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->name;
|
||||
}
|
||||
|
||||
int NameRecord::priority() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->priority;
|
||||
}
|
||||
|
||||
int NameRecord::weight() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->weight;
|
||||
}
|
||||
|
||||
int NameRecord::port() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->port;
|
||||
}
|
||||
|
||||
QList<QByteArray> NameRecord::texts() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->texts;
|
||||
}
|
||||
|
||||
QByteArray NameRecord::cpu() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->cpu;
|
||||
}
|
||||
|
||||
QByteArray NameRecord::os() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->os;
|
||||
}
|
||||
|
||||
QByteArray NameRecord::rawData() const
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
return d->rawData;
|
||||
}
|
||||
|
||||
void NameRecord::setOwner(const QByteArray &name)
|
||||
{
|
||||
ENSURE_D
|
||||
d->owner = name;
|
||||
}
|
||||
|
||||
void NameRecord::setTTL(int seconds)
|
||||
{
|
||||
ENSURE_D
|
||||
d->ttl = seconds;
|
||||
}
|
||||
|
||||
void NameRecord::setAddress(const QHostAddress &a)
|
||||
{
|
||||
ENSURE_D
|
||||
if(a.protocol() == QAbstractSocket::IPv6Protocol)
|
||||
d->type = NameRecord::Aaaa;
|
||||
else
|
||||
d->type = NameRecord::A;
|
||||
d->address = a;
|
||||
}
|
||||
|
||||
void NameRecord::setMx(const QByteArray &name, int priority)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Mx;
|
||||
d->name = name;
|
||||
d->priority = priority;
|
||||
}
|
||||
|
||||
void NameRecord::setSrv(const QByteArray &name, int port, int priority, int weight)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Srv;
|
||||
d->name = name;
|
||||
d->port = port;
|
||||
d->priority = priority;
|
||||
d->weight = weight;
|
||||
}
|
||||
|
||||
void NameRecord::setCname(const QByteArray &name)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Cname;
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
void NameRecord::setPtr(const QByteArray &name)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Ptr;
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
void NameRecord::setTxt(const QList<QByteArray> &texts)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Txt;
|
||||
d->texts = texts;
|
||||
}
|
||||
|
||||
void NameRecord::setHinfo(const QByteArray &cpu, const QByteArray &os)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Hinfo;
|
||||
d->cpu = cpu;
|
||||
d->os = os;
|
||||
}
|
||||
|
||||
void NameRecord::setNs(const QByteArray &name)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Ns;
|
||||
d->name = name;
|
||||
}
|
||||
|
||||
void NameRecord::setNull(const QByteArray &rawData)
|
||||
{
|
||||
ENSURE_D
|
||||
d->type = NameRecord::Null;
|
||||
d->rawData = rawData;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ServiceInstance
|
||||
//----------------------------------------------------------------------------
|
||||
class ServiceInstance::Private : public QSharedData
|
||||
{
|
||||
public:
|
||||
QString instance, type, domain;
|
||||
QMap<QString,QByteArray> attribs;
|
||||
QByteArray name;
|
||||
};
|
||||
|
||||
ServiceInstance::ServiceInstance()
|
||||
{
|
||||
d = new Private;
|
||||
}
|
||||
|
||||
ServiceInstance::ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap<QString,QByteArray> &attribs)
|
||||
{
|
||||
d = new Private;
|
||||
d->instance = instance;
|
||||
d->type = type;
|
||||
d->domain = domain;
|
||||
d->attribs = attribs;
|
||||
|
||||
// FIXME: escape the items
|
||||
d->name = instance.toLatin1() + '.' + type.toLatin1() + '.' + domain.toLatin1();
|
||||
}
|
||||
|
||||
ServiceInstance::ServiceInstance(const ServiceInstance &from)
|
||||
{
|
||||
d = 0;
|
||||
*this = from;
|
||||
}
|
||||
|
||||
ServiceInstance::~ServiceInstance()
|
||||
{
|
||||
}
|
||||
|
||||
ServiceInstance & ServiceInstance::operator=(const ServiceInstance &from)
|
||||
{
|
||||
d = from.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QString ServiceInstance::instance() const
|
||||
{
|
||||
return d->instance;
|
||||
}
|
||||
|
||||
QString ServiceInstance::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
QString ServiceInstance::domain() const
|
||||
{
|
||||
return d->domain;
|
||||
}
|
||||
|
||||
QMap<QString,QByteArray> ServiceInstance::attributes() const
|
||||
{
|
||||
return d->attribs;
|
||||
}
|
||||
|
||||
QByteArray ServiceInstance::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NameManager
|
||||
//----------------------------------------------------------------------------
|
||||
class NameManager;
|
||||
|
||||
Q_GLOBAL_STATIC(QMutex, nman_mutex)
|
||||
static NameManager *g_nman = 0;
|
||||
|
||||
class NameResolver::Private
|
||||
{
|
||||
public:
|
||||
NameResolver *q;
|
||||
|
||||
int type;
|
||||
bool longLived;
|
||||
int id;
|
||||
|
||||
Private(NameResolver *_q) : q(_q)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ServiceBrowser::Private
|
||||
{
|
||||
public:
|
||||
ServiceBrowser *q;
|
||||
|
||||
int id;
|
||||
|
||||
Private(ServiceBrowser *_q) : q(_q)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ServiceResolver::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServiceResolver *q;
|
||||
|
||||
int id;
|
||||
|
||||
int mode;
|
||||
NameResolver dns;
|
||||
int port;
|
||||
|
||||
class Server
|
||||
{
|
||||
public:
|
||||
QByteArray host;
|
||||
int port;
|
||||
int priority;
|
||||
int weight;
|
||||
};
|
||||
|
||||
QList<Server> servers;
|
||||
QList<QHostAddress> addrs;
|
||||
|
||||
Private(ServiceResolver *_q) : q(_q)
|
||||
{
|
||||
mode = 3;
|
||||
connect(&dns, SIGNAL(resultsReady(const QList<XMPP::NameRecord> &)), SLOT(dns_resultsReady(const QList<XMPP::NameRecord> &)));
|
||||
connect(&dns, SIGNAL(error(XMPP::NameResolver::Error)), SLOT(dns_error(XMPP::NameResolver::Error)));
|
||||
}
|
||||
|
||||
void tryNext()
|
||||
{
|
||||
if(mode == 3)
|
||||
{
|
||||
QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection);
|
||||
}
|
||||
if(mode == 2)
|
||||
{
|
||||
if(!addrs.isEmpty())
|
||||
{
|
||||
QHostAddress addr = addrs.takeFirst();
|
||||
QMetaObject::invokeMethod(q, "resultsReady", Qt::QueuedConnection, Q_ARG(QHostAddress, addr), Q_ARG(int, port));
|
||||
return;
|
||||
}
|
||||
|
||||
if(servers.isEmpty())
|
||||
{
|
||||
QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
Server serv = servers.takeFirst();
|
||||
port = serv.port;
|
||||
dns.start(serv.host, NameRecord::A); // TODO: ipv6!
|
||||
}
|
||||
else
|
||||
{
|
||||
if(addrs.isEmpty())
|
||||
{
|
||||
QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
QHostAddress addr = addrs.takeFirst();
|
||||
QMetaObject::invokeMethod(q, "resultsReady", Qt::QueuedConnection, Q_ARG(QHostAddress, addr), Q_ARG(int, port));
|
||||
}
|
||||
}
|
||||
|
||||
private slots:
|
||||
void dns_resultsReady(const QList<XMPP::NameRecord> &results)
|
||||
{
|
||||
if(mode == 0)
|
||||
{
|
||||
mode = 2;
|
||||
servers.clear();
|
||||
for(int n = 0; n < results.count(); ++n)
|
||||
{
|
||||
Server serv;
|
||||
serv.host = results[n].name();
|
||||
serv.port = results[n].port();
|
||||
serv.priority = results[n].priority();
|
||||
serv.weight = results[n].weight();
|
||||
servers += serv;
|
||||
}
|
||||
tryNext();
|
||||
}
|
||||
else if(mode == 1)
|
||||
{
|
||||
addrs.clear();
|
||||
|
||||
// TODO: don't forget about ipv6
|
||||
for(int n = 0; n < results.count(); ++n)
|
||||
addrs += results[n].address();
|
||||
|
||||
tryNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
QList<QHostAddress> tmp;
|
||||
for(int n = 0; n < results.count(); ++n)
|
||||
tmp += results[n].address();
|
||||
|
||||
addrs += tmp;
|
||||
tryNext();
|
||||
}
|
||||
}
|
||||
|
||||
void dns_error(XMPP::NameResolver::Error)
|
||||
{
|
||||
if(mode == 0 || mode == 1)
|
||||
emit q->error();
|
||||
else
|
||||
tryNext(); // FIXME: probably shouldn't share this
|
||||
}
|
||||
};
|
||||
|
||||
class ServiceLocalPublisher::Private
|
||||
{
|
||||
public:
|
||||
ServiceLocalPublisher *q;
|
||||
|
||||
int id;
|
||||
|
||||
Private(ServiceLocalPublisher *_q) : q(_q)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class NameManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NameProvider *p_net, *p_local;
|
||||
ServiceProvider *p_serv;
|
||||
QHash<int,NameResolver::Private*> res_instances;
|
||||
QHash<int,int> res_sub_instances;
|
||||
|
||||
QHash<int,ServiceBrowser::Private*> br_instances;
|
||||
QHash<int,ServiceResolver::Private*> sres_instances;
|
||||
QHash<int,ServiceLocalPublisher::Private*> slp_instances;
|
||||
|
||||
NameManager(QObject *parent = 0) : QObject(parent)
|
||||
{
|
||||
p_net = 0;
|
||||
p_local = 0;
|
||||
p_serv = 0;
|
||||
}
|
||||
|
||||
~NameManager()
|
||||
{
|
||||
delete p_net;
|
||||
delete p_local;
|
||||
delete p_serv;
|
||||
}
|
||||
|
||||
static NameManager *instance()
|
||||
{
|
||||
QMutexLocker locker(nman_mutex());
|
||||
if(!g_nman)
|
||||
{
|
||||
g_nman = new NameManager;
|
||||
irisNetAddPostRoutine(NetNames::cleanup);
|
||||
}
|
||||
return g_nman;
|
||||
}
|
||||
|
||||
static void cleanup()
|
||||
{
|
||||
delete g_nman;
|
||||
g_nman = 0;
|
||||
}
|
||||
|
||||
void resolve_start(NameResolver::Private *np, const QByteArray &name, int qType, bool longLived)
|
||||
{
|
||||
QMutexLocker locker(nman_mutex());
|
||||
|
||||
np->type = qType;
|
||||
np->longLived = longLived;
|
||||
if(!p_net)
|
||||
{
|
||||
NameProvider *c = 0;
|
||||
QList<IrisNetProvider*> list = irisNetProviders();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
IrisNetProvider *p = list[n];
|
||||
c = p->createNameProviderInternet();
|
||||
if(c)
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(c); // we have built-in support, so this should never fail
|
||||
p_net = c;
|
||||
|
||||
// use queued connections
|
||||
qRegisterMetaType< QList<XMPP::NameRecord> >("QList<XMPP::NameRecord>");
|
||||
qRegisterMetaType<XMPP::NameResolver::Error>("XMPP::NameResolver::Error");
|
||||
connect(p_net, SIGNAL(resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), SLOT(provider_resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), Qt::QueuedConnection);
|
||||
connect(p_net, SIGNAL(resolve_error(int, XMPP::NameResolver::Error)), SLOT(provider_resolve_error(int, XMPP::NameResolver::Error)), Qt::QueuedConnection);
|
||||
connect(p_net, SIGNAL(resolve_useLocal(int, const QByteArray &)), SLOT(provider_resolve_useLocal(int, const QByteArray &)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
np->id = p_net->resolve_start(name, qType, longLived);
|
||||
|
||||
//printf("assigning %d to %p\n", req_id, np);
|
||||
res_instances.insert(np->id, np);
|
||||
}
|
||||
|
||||
void browse_start(ServiceBrowser::Private *np, const QString &type, const QString &domain)
|
||||
{
|
||||
QMutexLocker locker(nman_mutex());
|
||||
|
||||
if(!p_serv)
|
||||
{
|
||||
ServiceProvider *c = 0;
|
||||
QList<IrisNetProvider*> list = irisNetProviders();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
IrisNetProvider *p = list[n];
|
||||
c = p->createServiceProvider();
|
||||
if(c)
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(c); // we have built-in support, so this should never fail
|
||||
p_serv = c;
|
||||
|
||||
// use queued connections
|
||||
qRegisterMetaType<XMPP::ServiceInstance>("XMPP::ServiceInstance");
|
||||
connect(p_serv, SIGNAL(browse_instanceAvailable(int, const XMPP::ServiceInstance &)), SLOT(provider_browse_instanceAvailable(int, const XMPP::ServiceInstance &)), Qt::QueuedConnection);
|
||||
connect(p_serv, SIGNAL(browse_instanceUnavailable(int, const XMPP::ServiceInstance &)), SLOT(provider_browse_instanceUnavailable(int, const XMPP::ServiceInstance &)), Qt::QueuedConnection);
|
||||
connect(p_serv, SIGNAL(browse_error(int)), SLOT(provider_browse_error(int)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
/*np->id = */
|
||||
|
||||
np->id = p_serv->browse_start(type, domain);
|
||||
|
||||
br_instances.insert(np->id, np);
|
||||
}
|
||||
|
||||
void resolve_instance_start(ServiceResolver::Private *np, const QByteArray &name)
|
||||
{
|
||||
QMutexLocker locker(nman_mutex());
|
||||
|
||||
if(!p_serv)
|
||||
{
|
||||
ServiceProvider *c = 0;
|
||||
QList<IrisNetProvider*> list = irisNetProviders();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
IrisNetProvider *p = list[n];
|
||||
c = p->createServiceProvider();
|
||||
if(c)
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(c); // we have built-in support, so this should never fail
|
||||
p_serv = c;
|
||||
|
||||
// use queued connections
|
||||
qRegisterMetaType<QHostAddress>("QHostAddress");
|
||||
connect(p_serv, SIGNAL(resolve_resultsReady(int, const QHostAddress &, int)), SLOT(provider_resolve_resultsReady(int, const QHostAddress &, int)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
/*np->id = */
|
||||
|
||||
np->id = p_serv->resolve_start(name);
|
||||
|
||||
sres_instances.insert(np->id, np);
|
||||
}
|
||||
|
||||
void publish_start(ServiceLocalPublisher::Private *np, const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attribs)
|
||||
{
|
||||
QMutexLocker locker(nman_mutex());
|
||||
|
||||
if(!p_serv)
|
||||
{
|
||||
ServiceProvider *c = 0;
|
||||
QList<IrisNetProvider*> list = irisNetProviders();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
IrisNetProvider *p = list[n];
|
||||
c = p->createServiceProvider();
|
||||
if(c)
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(c); // we have built-in support, so this should never fail
|
||||
p_serv = c;
|
||||
|
||||
// use queued connections
|
||||
qRegisterMetaType<XMPP::ServiceLocalPublisher::Error>("XMPP::ServiceLocalPublisher::Error");
|
||||
connect(p_serv, SIGNAL(publish_published(int)), SLOT(provider_publish_published(int)), Qt::QueuedConnection);
|
||||
connect(p_serv, SIGNAL(publish_extra_published(int)), SLOT(provider_publish_extra_published(int)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
/*np->id = */
|
||||
|
||||
np->id = p_serv->publish_start(instance, type, port, attribs);
|
||||
|
||||
slp_instances.insert(np->id, np);
|
||||
}
|
||||
|
||||
void publish_extra_start(ServiceLocalPublisher::Private *np, const NameRecord &rec)
|
||||
{
|
||||
np->id = p_serv->publish_extra_start(np->id, rec);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void provider_resolve_resultsReady(int id, const QList<XMPP::NameRecord> &results)
|
||||
{
|
||||
// is it a sub-request?
|
||||
if(res_sub_instances.contains(id))
|
||||
{
|
||||
int par_id = res_sub_instances.value(id);
|
||||
res_sub_instances.remove(id);
|
||||
p_net->resolve_localResultsReady(par_id, results);
|
||||
return;
|
||||
}
|
||||
|
||||
NameResolver::Private *np = res_instances.value(id);
|
||||
emit np->q->resultsReady(results);
|
||||
}
|
||||
|
||||
void provider_resolve_error(int id, XMPP::NameResolver::Error e)
|
||||
{
|
||||
// is it a sub-request?
|
||||
if(res_sub_instances.contains(id))
|
||||
{
|
||||
int par_id = res_sub_instances.value(id);
|
||||
res_sub_instances.remove(id);
|
||||
p_net->resolve_localError(par_id, e);
|
||||
return;
|
||||
}
|
||||
|
||||
NameResolver::Private *np = res_instances.value(id);
|
||||
emit np->q->error(e);
|
||||
}
|
||||
|
||||
void provider_resolve_useLocal(int id, const QByteArray &name)
|
||||
{
|
||||
// transfer to local
|
||||
if(!p_local)
|
||||
{
|
||||
NameProvider *c = 0;
|
||||
QList<IrisNetProvider*> list = irisNetProviders();
|
||||
for(int n = 0; n < list.count(); ++n)
|
||||
{
|
||||
IrisNetProvider *p = list[n];
|
||||
c = p->createNameProviderLocal();
|
||||
if(c)
|
||||
break;
|
||||
}
|
||||
Q_ASSERT(c); // we have built-in support, so this should never fail
|
||||
// FIXME: not true, binding can fail
|
||||
p_local = c;
|
||||
|
||||
// use queued connections
|
||||
qRegisterMetaType< QList<XMPP::NameRecord> >("QList<XMPP::NameRecord>");
|
||||
qRegisterMetaType<XMPP::NameResolver::Error>("XMPP::NameResolver::Error");
|
||||
connect(p_local, SIGNAL(resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), SLOT(provider_resolve_resultsReady(int, const QList<XMPP::NameRecord> &)), Qt::QueuedConnection);
|
||||
connect(p_local, SIGNAL(resolve_error(int, XMPP::NameResolver::Error)), SLOT(provider_resolve_error(int, XMPP::NameResolver::Error)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
NameResolver::Private *np = res_instances.value(id);
|
||||
|
||||
// transfer to local only
|
||||
if(np->longLived)
|
||||
{
|
||||
res_instances.remove(np->id);
|
||||
|
||||
np->id = p_local->resolve_start(name, np->type, true);
|
||||
res_instances.insert(np->id, np);
|
||||
}
|
||||
// sub request
|
||||
else
|
||||
{
|
||||
int req_id = p_local->resolve_start(name, np->type, false);
|
||||
|
||||
res_sub_instances.insert(req_id, np->id);
|
||||
}
|
||||
}
|
||||
|
||||
void provider_browse_instanceAvailable(int id, const XMPP::ServiceInstance &i)
|
||||
{
|
||||
ServiceBrowser::Private *np = br_instances.value(id);
|
||||
emit np->q->instanceAvailable(i);
|
||||
}
|
||||
|
||||
void provider_browse_instanceUnavailable(int id, const XMPP::ServiceInstance &i)
|
||||
{
|
||||
ServiceBrowser::Private *np = br_instances.value(id);
|
||||
emit np->q->instanceUnavailable(i);
|
||||
}
|
||||
|
||||
void provider_browse_error(int id)
|
||||
{
|
||||
ServiceBrowser::Private *np = br_instances.value(id);
|
||||
// TODO
|
||||
emit np->q->error();
|
||||
}
|
||||
|
||||
void provider_resolve_resultsReady(int id, const QHostAddress &addr, int port)
|
||||
{
|
||||
ServiceResolver::Private *np = sres_instances.value(id);
|
||||
emit np->q->resultsReady(addr, port);
|
||||
}
|
||||
|
||||
void provider_publish_published(int id)
|
||||
{
|
||||
ServiceLocalPublisher::Private *np = slp_instances.value(id);
|
||||
emit np->q->published();
|
||||
}
|
||||
|
||||
void provider_publish_extra_published(int id)
|
||||
{
|
||||
Q_UNUSED(id);
|
||||
//ServiceLocalPublisher::Private *np = slp_instances.value(id);
|
||||
//emit np->q->published();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NameResolver
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// copied from JDNS
|
||||
#define JDNS_RTYPE_A 1
|
||||
#define JDNS_RTYPE_AAAA 28
|
||||
#define JDNS_RTYPE_MX 15
|
||||
#define JDNS_RTYPE_SRV 33
|
||||
#define JDNS_RTYPE_CNAME 5
|
||||
#define JDNS_RTYPE_PTR 12
|
||||
#define JDNS_RTYPE_TXT 16
|
||||
#define JDNS_RTYPE_HINFO 13
|
||||
#define JDNS_RTYPE_NS 2
|
||||
#define JDNS_RTYPE_ANY 255
|
||||
|
||||
static int recordType2Rtype(NameRecord::Type type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case NameRecord::A: return JDNS_RTYPE_A;
|
||||
case NameRecord::Aaaa: return JDNS_RTYPE_AAAA;
|
||||
case NameRecord::Mx: return JDNS_RTYPE_MX;
|
||||
case NameRecord::Srv: return JDNS_RTYPE_SRV;
|
||||
case NameRecord::Cname: return JDNS_RTYPE_CNAME;
|
||||
case NameRecord::Ptr: return JDNS_RTYPE_PTR;
|
||||
case NameRecord::Txt: return JDNS_RTYPE_TXT;
|
||||
case NameRecord::Hinfo: return JDNS_RTYPE_HINFO;
|
||||
case NameRecord::Ns: return JDNS_RTYPE_NS;
|
||||
case NameRecord::Null: return 10;
|
||||
case NameRecord::Any: return JDNS_RTYPE_ANY;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
NameResolver::NameResolver(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
NameResolver::~NameResolver()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void NameResolver::start(const QByteArray &name, NameRecord::Type type, Mode mode)
|
||||
{
|
||||
int qType = recordType2Rtype(type);
|
||||
if(qType == -1)
|
||||
qType = JDNS_RTYPE_A;
|
||||
NameManager::instance()->resolve_start(d, name, qType, mode == NameResolver::LongLived ? true : false);
|
||||
}
|
||||
|
||||
void NameResolver::stop()
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ServiceBrowser
|
||||
//----------------------------------------------------------------------------
|
||||
ServiceBrowser::ServiceBrowser(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
ServiceBrowser::~ServiceBrowser()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ServiceBrowser::start(const QString &type, const QString &domain)
|
||||
{
|
||||
NameManager::instance()->browse_start(d, type, domain);
|
||||
}
|
||||
|
||||
void ServiceBrowser::stop()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ServiceResolver
|
||||
//----------------------------------------------------------------------------
|
||||
ServiceResolver::ServiceResolver(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
qRegisterMetaType<QHostAddress>("QHostAddress");
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
ServiceResolver::~ServiceResolver()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ServiceResolver::startFromInstance(const QByteArray &name)
|
||||
{
|
||||
NameManager::instance()->resolve_instance_start(d, name);
|
||||
}
|
||||
|
||||
void ServiceResolver::startFromDomain(const QString &domain, const QString &type)
|
||||
{
|
||||
d->mode = 0;
|
||||
d->dns.start(type.toLatin1() + '.' + domain.toLatin1(), NameRecord::Srv);
|
||||
}
|
||||
|
||||
void ServiceResolver::startFromPlain(const QString &host, int port)
|
||||
{
|
||||
d->mode = 1;
|
||||
d->port = port;
|
||||
d->dns.start(host.toLatin1(), NameRecord::A); // TODO: try Aaaa first, fallback to A
|
||||
}
|
||||
|
||||
void ServiceResolver::tryNext()
|
||||
{
|
||||
d->tryNext();
|
||||
}
|
||||
|
||||
void ServiceResolver::stop()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ServiceLocalPublisher
|
||||
//----------------------------------------------------------------------------
|
||||
ServiceLocalPublisher::ServiceLocalPublisher(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
ServiceLocalPublisher::~ServiceLocalPublisher()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ServiceLocalPublisher::publish(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes)
|
||||
{
|
||||
NameManager::instance()->publish_start(d, instance, type, port, attributes);
|
||||
}
|
||||
|
||||
void ServiceLocalPublisher::updateAttributes(const QMap<QString,QByteArray> &attributes)
|
||||
{
|
||||
Q_UNUSED(attributes);
|
||||
}
|
||||
|
||||
void ServiceLocalPublisher::addRecord(const NameRecord &rec)
|
||||
{
|
||||
NameManager::instance()->publish_extra_start(d, rec);
|
||||
}
|
||||
|
||||
void ServiceLocalPublisher::cancel()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// NetNames
|
||||
//----------------------------------------------------------------------------
|
||||
void NetNames::cleanup()
|
||||
{
|
||||
NameManager::cleanup();
|
||||
}
|
||||
|
||||
QString NetNames::diagnosticText()
|
||||
{
|
||||
// TODO
|
||||
return QString();
|
||||
}
|
||||
|
||||
QByteArray NetNames::idnaFromString(const QString &in)
|
||||
{
|
||||
// TODO
|
||||
Q_UNUSED(in);
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QString NetNames::idnaToString(const QByteArray &in)
|
||||
{
|
||||
// TODO
|
||||
Q_UNUSED(in);
|
||||
return QString();
|
||||
}
|
||||
|
||||
QByteArray NetNames::escapeDomain(const QByteArray &in)
|
||||
{
|
||||
// TODO
|
||||
Q_UNUSED(in);
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray NetNames::unescapeDomain(const QByteArray &in)
|
||||
{
|
||||
// TODO
|
||||
Q_UNUSED(in);
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "netnames.moc"
|
||||
537
iris-legacy/iris/irisnet/netnames.h
Normal file
537
iris-legacy/iris/irisnet/netnames.h
Normal file
|
|
@ -0,0 +1,537 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NETNAMES_H
|
||||
#define NETNAMES_H
|
||||
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include "irisnetglobal.h"
|
||||
|
||||
namespace XMPP {
|
||||
|
||||
class NameManager;
|
||||
|
||||
class IRISNET_EXPORT NetNames
|
||||
{
|
||||
public:
|
||||
// free any shared data, shutdown internal dns sessions if necessary.
|
||||
static void cleanup();
|
||||
|
||||
// return current diagnostic text, clear the buffer.
|
||||
static QString diagnosticText();
|
||||
|
||||
// convert idn names
|
||||
static QByteArray idnaFromString(const QString &in);
|
||||
static QString idnaToString(const QByteArray &in);
|
||||
|
||||
// dns escaping
|
||||
static QByteArray escapeDomain(const QByteArray &in);
|
||||
static QByteArray unescapeDomain(const QByteArray &in);
|
||||
|
||||
private:
|
||||
NetNames();
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Provides a DNS record
|
||||
|
||||
NameRecord provides a DNS (Domain Name System) record, which is information assicated with a domain name. For most purposes, the information is an IP address. However, DNS records are capable of holding a variety of data types, such as named pointers to other domain names and even arbitrary text strings. The results of a NameResolver operation are a list of NameRecords.
|
||||
|
||||
The most common type is the address record, "A", which contains an IPv4 address. Here is an example of how to get the IP address out of an address record:
|
||||
|
||||
\code
|
||||
NameRecord record = ... // obtain a record from somewhere
|
||||
if(record.type() == NameRecord::A)
|
||||
{
|
||||
QHostAddress ip = record.address(); // get the IP
|
||||
...
|
||||
}
|
||||
\endcode
|
||||
|
||||
Getting the data out of a NameRecord involves calling the right retrieval functions, depending on the type. Many types share retrieval functions. For example, the "AAAA" type holds an IPv6 address, which is accessed the same way as the "A" type, by calling address(). See the NameRecord::Type enum for further information about which retrieval functions should be called for each type.
|
||||
|
||||
To create a NameRecord, use setOwner() and setTTL() as necessary, and then call one of the set<em>X</em> functions (where <em>X</em> is the desired type). For example, to set an A or AAAA record, use setAddress() like this:
|
||||
|
||||
\code
|
||||
// make example.com the owner, with 1 hour TTL
|
||||
NameRecord record("example.com", 3600);
|
||||
record.setAddress(QHostAddress("1.2.3.4"));
|
||||
\endcode
|
||||
|
||||
Note that in the case of setAddress(), the record type need not be specified. NameRecord will determine the type to use based on the given QHostAddress.
|
||||
|
||||
\sa NameResolver
|
||||
*/
|
||||
class IRISNET_EXPORT NameRecord
|
||||
{
|
||||
public:
|
||||
/**
|
||||
\brief The type of DNS record
|
||||
|
||||
The retrieval functions are shown for each type.
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
A, ///< IPv4 address. Use address().
|
||||
Aaaa, ///< IPv6 address. Use address().
|
||||
Mx, ///< Mail server. Use name() and priority().
|
||||
Srv, ///< Generic server. Use name(), port(), priority(), and weight().
|
||||
Cname, ///< Canonical name. Use name().
|
||||
Ptr, ///< Pointer. Use name().
|
||||
Txt, ///< List of text strings. Use texts().
|
||||
Hinfo, ///< Host information. Use cpu() and os().
|
||||
Ns, ///< Name server. Use name().
|
||||
Null, ///< Null type. Use rawData().
|
||||
Any ///< "Any record", for use with NameResolver::start() only. A NameRecord object will never be of this type.
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Constructs a null record object
|
||||
|
||||
\sa isNull
|
||||
*/
|
||||
NameRecord();
|
||||
|
||||
/**
|
||||
\brief Constructs a partially initialized record object, with the given \a owner and \a ttl
|
||||
|
||||
For the record to be usable, call an appropriate set<em>X</em> function (where <em>X</em> is the desired type) afterwards.
|
||||
*/
|
||||
NameRecord(const QByteArray &owner, int ttl);
|
||||
|
||||
/**
|
||||
\brief Constructs a copy of \a from
|
||||
*/
|
||||
NameRecord(const NameRecord &from);
|
||||
|
||||
/**
|
||||
\brief Destroys the record object
|
||||
*/
|
||||
~NameRecord();
|
||||
|
||||
/**
|
||||
\brief Assigns \a from to this object and returns a reference to this object
|
||||
*/
|
||||
NameRecord & operator=(const NameRecord &from);
|
||||
|
||||
/**
|
||||
\brief Returns true if this record object is null, otherwise returns false
|
||||
|
||||
Be sure not to confuse a null object with the NULL type (NameRecord::Null). Don't ask why DNS has a type called NULL that contains valid data.
|
||||
*/
|
||||
bool isNull() const; // don't confuse with Null type
|
||||
|
||||
/**
|
||||
\brief Returns the owner of this record
|
||||
|
||||
The owner is usually not a useful attribute, since it will be the same as the name searched for with NameResolver. For example, if the A record of "example.com" is looked up, then the resulting records will all have "example.com" as the owner.
|
||||
|
||||
\sa setOwner
|
||||
*/
|
||||
QByteArray owner() const;
|
||||
|
||||
/**
|
||||
\brief Returns the TTL (time-to-live) of this record
|
||||
|
||||
This is the number of seconds the record should be considered valid, which is useful information when performing caching.
|
||||
|
||||
As a special exception, a TTL of 0 when performing a long-lived lookup indicates that a record is no longer available.
|
||||
|
||||
\sa setTTL
|
||||
*/
|
||||
int ttl() const;
|
||||
|
||||
/**
|
||||
\brief Returns the type of this record
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/**
|
||||
\brief Returns the IP address
|
||||
|
||||
For NameRecord::A and NameRecord::Aaaa types.
|
||||
*/
|
||||
QHostAddress address() const;
|
||||
|
||||
/**
|
||||
\brief Returns the domain name
|
||||
|
||||
For NameRecord::Mx, NameRecord::Srv, NameRecord::Cname, NameRecord::Ptr, and NameRecord::Ns types.
|
||||
*/
|
||||
QByteArray name() const;
|
||||
|
||||
/**
|
||||
\brief Returns the priority
|
||||
|
||||
For NameRecord::Mx and NameRecord::Srv types.
|
||||
*/
|
||||
int priority() const;
|
||||
|
||||
/**
|
||||
\brief Returns the weight
|
||||
|
||||
For the NameRecord::Srv type.
|
||||
*/
|
||||
int weight() const;
|
||||
|
||||
/**
|
||||
\brief Returns the port
|
||||
|
||||
For the NameRecord::Srv type.
|
||||
*/
|
||||
int port() const;
|
||||
|
||||
/**
|
||||
\brief Returns the list of text strings
|
||||
|
||||
For the NameRecord::Txt type.
|
||||
*/
|
||||
QList<QByteArray> texts() const;
|
||||
|
||||
/**
|
||||
\brief Returns the architecture identifier string
|
||||
|
||||
For the NameRecord::Hinfo type.
|
||||
*/
|
||||
QByteArray cpu() const;
|
||||
|
||||
/**
|
||||
\brief Returns the operating system identifier string
|
||||
|
||||
For the NameRecord::Hinfo type.
|
||||
*/
|
||||
QByteArray os() const;
|
||||
|
||||
/**
|
||||
\brief Returns the raw data
|
||||
|
||||
For the NameRecord::Null type.
|
||||
*/
|
||||
QByteArray rawData() const;
|
||||
|
||||
/**
|
||||
\brief Sets the owner of this record to \a name
|
||||
|
||||
\sa owner
|
||||
*/
|
||||
void setOwner(const QByteArray &name);
|
||||
|
||||
/**
|
||||
\brief Sets the TTL (time-to-live) of this record to \a ttl seconds
|
||||
|
||||
\sa ttl
|
||||
*/
|
||||
void setTTL(int seconds);
|
||||
|
||||
/**
|
||||
\brief Set as A or AAAA record, with data \a a
|
||||
|
||||
The protocol of \a a determines whether the type will be NameRecord::A or NameRecord::Aaaa.
|
||||
*/
|
||||
void setAddress(const QHostAddress &a);
|
||||
|
||||
/**
|
||||
\brief Set as MX record, with data \a name and \a priority
|
||||
*/
|
||||
void setMx(const QByteArray &name, int priority);
|
||||
|
||||
/**
|
||||
\brief Set as SRV record, with data \a name, \a port, \a priority, and \a weight
|
||||
*/
|
||||
void setSrv(const QByteArray &name, int port, int priority, int weight);
|
||||
|
||||
/**
|
||||
\brief Set as CNAME record, with data \a name
|
||||
*/
|
||||
void setCname(const QByteArray &name);
|
||||
|
||||
/**
|
||||
\brief Set as PTR record, with data \a name
|
||||
*/
|
||||
void setPtr(const QByteArray &name);
|
||||
|
||||
/**
|
||||
\brief Set as TXT record, with data \a texts
|
||||
*/
|
||||
void setTxt(const QList<QByteArray> &texts);
|
||||
|
||||
/**
|
||||
\brief Set as HINFO record, with data \a cpu and \a os
|
||||
*/
|
||||
void setHinfo(const QByteArray &cpu, const QByteArray &os);
|
||||
|
||||
/**
|
||||
\brief Set as NS record, with data \a name
|
||||
*/
|
||||
void setNs(const QByteArray &name);
|
||||
|
||||
/**
|
||||
\brief Set as NULL record, with data \a rawData
|
||||
*/
|
||||
void setNull(const QByteArray &rawData);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QSharedDataPointer<Private> d;
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT ServiceInstance
|
||||
{
|
||||
public:
|
||||
ServiceInstance();
|
||||
ServiceInstance(const QString &instance, const QString &type, const QString &domain, const QMap<QString,QByteArray> &attributes);
|
||||
ServiceInstance(const ServiceInstance &from);
|
||||
~ServiceInstance();
|
||||
ServiceInstance & operator=(const ServiceInstance &from);
|
||||
|
||||
QString instance() const;
|
||||
QString type() const;
|
||||
QString domain() const;
|
||||
QMap<QString,QByteArray> attributes() const;
|
||||
QByteArray name() const; // full dns label
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QSharedDataPointer<Private> d;
|
||||
|
||||
friend class NameManager;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Performs a DNS lookup
|
||||
|
||||
NameResolver performs an asynchronous DNS lookup for a given domain name and record type. Call start() to begin. The resultsReady() signal is emitted on success, otherwise error() is emitted. To cancel a lookup, call stop().
|
||||
|
||||
For example, here is how to obtain the IPv4 addresses of a domain name:
|
||||
\code
|
||||
NameResolver *resolver;
|
||||
|
||||
void do_lookup()
|
||||
{
|
||||
resolver = new NameResolver;
|
||||
connect(resolver, SIGNAL(resultsReady(const QList<XMPP::NameRecord> &)),
|
||||
SLOT(dns_resultsReady(const QList<XMPP::NameRecord> &)));
|
||||
connect(resolver, SIGNAL(error(XMPP::NameResolver::Error)),
|
||||
SLOT(dns_error(XMPP::NameResolver::Error)));
|
||||
|
||||
// look up affinix.com
|
||||
resolver->start("affinix.com");
|
||||
}
|
||||
|
||||
void dns_resultsReady(const QList<XMPP::NameRecord> &results)
|
||||
{
|
||||
// print IP addresses
|
||||
foreach(NameRecord i, results)
|
||||
printf("%s\n", qPrintable(i.address().toString()));
|
||||
}
|
||||
|
||||
void dns_error(XMPP::NameResolver::Error error)
|
||||
{
|
||||
// handle error
|
||||
...
|
||||
}
|
||||
\endcode
|
||||
|
||||
Yes, a domain name can have multiple IP addresses. Many applications ignore this fact, and use only one of the answers. A proper network application should try connecting to each IP address until one succeeds.
|
||||
|
||||
To lookup other types, pass the desired type to start(). For example, suppose you want to look up the MX record of a domain name:
|
||||
|
||||
\code
|
||||
// look up the MX record for affinix.com
|
||||
resolver->start("affinix.com", NameRecord::Mx);
|
||||
\endcode
|
||||
|
||||
It is also possible to perform long-lived queries. This is generally useful for DNS Service Discovery. Long-lived queries are continuous, and resultsReady() may be emitted multiple times. Unlike a normal lookup, which stops once the results are returned, a long-lived query will keep going until stop() is called.
|
||||
|
||||
For example, suppose you want to scan the local network for SSH services. According to the DNS-SD protocol, this is done by querying for the name "_ssh._tcp.local." of type PTR.
|
||||
|
||||
\code
|
||||
// monitor for SSH services on the local network
|
||||
resolver->start("_ssh._tcp.local.", NameRecord::Ptr, NameResolver::LongLived);
|
||||
\endcode
|
||||
|
||||
Don't be alarmed by the trailing dot (".") character in this last example. It is not well known, but all valid DNS domain names end with a dot. However, NameResolver, like most DNS programming interfaces, allows the dot to be left out. What this means is that if a trailing dot is missing in the input to start(), NameResolver will internally append one before performing the query.
|
||||
|
||||
\sa NameRecord
|
||||
*/
|
||||
class IRISNET_EXPORT NameResolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief Resolve mode
|
||||
*/
|
||||
enum Mode
|
||||
{
|
||||
Single, ///< A normal DNS query with a single result set.
|
||||
LongLived ///< An endless query, with multiple result sets allowed.
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Resolve error
|
||||
*/
|
||||
enum Error
|
||||
{
|
||||
ErrorGeneric, ///< General failure during lookup, no further details.
|
||||
ErrorNoName, ///< Name does not exist.
|
||||
ErrorTimeout, ///< The operation timed out.
|
||||
ErrorNoLocal, ///< The query is to the local network, but no mechanism for Multicast DNS is available.
|
||||
ErrorNoLongLived ///< The query requires long-lived capability, but no mechanism for doing so is available.
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Constructs a new resolver object with the given \a parent
|
||||
*/
|
||||
NameResolver(QObject *parent = 0);
|
||||
|
||||
/**
|
||||
\brief Destroys the resolver object
|
||||
|
||||
The lookup is, of course, stopped.
|
||||
*/
|
||||
~NameResolver();
|
||||
|
||||
/**
|
||||
\brief Starts a lookup
|
||||
|
||||
A lookup for \a name of \a type is started. For normal queries, \a mode should be NameResolver::Single (this is the default). For long-lived queries, use NameResolver::LongLived.
|
||||
|
||||
\sa stop
|
||||
*/
|
||||
void start(const QByteArray &name, NameRecord::Type type = NameRecord::A, Mode mode = Single);
|
||||
|
||||
/**
|
||||
\brief Stops a lookup
|
||||
|
||||
Use this function if you want to stop the current lookup, such that the resolver object may be reused again later. If you don't plan to reuse the object, then destroying the object is enough.
|
||||
|
||||
\sa start
|
||||
*/
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Notification of result records
|
||||
|
||||
This signal is emitted when results of the lookup operation have arrived. The \a results parameter is a list of NameRecords. All records will be of the type queried for with start(), unless the NameRecord::Any type was specified, in which case the records may be of any type
|
||||
|
||||
When using the NameResolver::Single mode, the lookup is stopped once results are ready. However, with the NameResolver::LongLived mode, the lookup stays active, and in that case this signal may be emitted multiple times.
|
||||
*/
|
||||
void resultsReady(const QList<XMPP::NameRecord> &results);
|
||||
|
||||
/**
|
||||
\brief Notification of error
|
||||
|
||||
This signal is emitted if an error has occurred while performing a lookup. The reason for error can be found in \a e. Regardless of the mode used, the lookup is stopped when an error occurs.
|
||||
*/
|
||||
void error(XMPP::NameResolver::Error e);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
|
||||
friend class NameManager;
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT ServiceBrowser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServiceBrowser(QObject *parent = 0);
|
||||
~ServiceBrowser();
|
||||
|
||||
void start(const QString &type, const QString &domain = "local");
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void instanceAvailable(const XMPP::ServiceInstance &instance);
|
||||
void instanceUnavailable(const XMPP::ServiceInstance &instance);
|
||||
void error();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
|
||||
friend class NameManager;
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT ServiceResolver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ServiceResolver(QObject *parent = 0);
|
||||
~ServiceResolver();
|
||||
|
||||
void startFromInstance(const QByteArray &name);
|
||||
void startFromDomain(const QString &domain, const QString &type);
|
||||
void startFromPlain(const QString &host, int port); // non-SRV
|
||||
void tryNext();
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void resultsReady(const QHostAddress &address, int port);
|
||||
void finished();
|
||||
void error(); // SRV lookup failed
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
|
||||
friend class NameManager;
|
||||
};
|
||||
|
||||
class IRISNET_EXPORT ServiceLocalPublisher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Error
|
||||
{
|
||||
ErrorGeneric, // generic error
|
||||
ErrorConflict, // name in use
|
||||
ErrorNoLocal // unable to setup multicast dns
|
||||
};
|
||||
|
||||
ServiceLocalPublisher(QObject *parent = 0);
|
||||
~ServiceLocalPublisher();
|
||||
|
||||
void publish(const QString &instance, const QString &type, int port, const QMap<QString,QByteArray> &attributes);
|
||||
void updateAttributes(const QMap<QString,QByteArray> &attributes);
|
||||
void addRecord(const NameRecord &rec);
|
||||
void cancel();
|
||||
|
||||
signals:
|
||||
void published();
|
||||
void error(XMPP::ServiceLocalPublisher::Error e);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
|
||||
friend class NameManager;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1143
iris-legacy/iris/irisnet/netnames_jdns.cpp
Normal file
1143
iris-legacy/iris/irisnet/netnames_jdns.cpp
Normal file
File diff suppressed because it is too large
Load diff
222
iris-legacy/iris/irisnet/processquit.cpp
Normal file
222
iris-legacy/iris/irisnet/processquit.cpp
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "processquit.h"
|
||||
|
||||
#ifndef NO_IRISNET
|
||||
# include "irisnetglobal_p.h"
|
||||
#endif
|
||||
|
||||
#ifdef QT_GUI_LIB
|
||||
# include <QApplication>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
# include <signal.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef NO_IRISNET
|
||||
namespace XMPP {
|
||||
#endif
|
||||
|
||||
Q_GLOBAL_STATIC(QMutex, pq_mutex)
|
||||
static ProcessQuit *g_pq = 0;
|
||||
|
||||
inline bool is_gui_app()
|
||||
{
|
||||
#ifdef QT_GUI_LIB
|
||||
return (QApplication::type() != QApplication::Tty);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
class ProcessQuit::Private : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ProcessQuit *q;
|
||||
|
||||
bool done;
|
||||
#ifdef Q_OS_WIN
|
||||
bool use_handler;
|
||||
#endif
|
||||
#ifdef Q_OS_UNIX
|
||||
int sig_pipe[2];
|
||||
QSocketNotifier *sig_notifier;
|
||||
#endif
|
||||
|
||||
Private(ProcessQuit *_q) : QObject(_q), q(_q)
|
||||
{
|
||||
done = false;
|
||||
#ifdef Q_OS_WIN
|
||||
use_handler = !is_gui_app();
|
||||
if(use_handler)
|
||||
SetConsoleCtrlHandler((PHANDLER_ROUTINE)winHandler, TRUE);
|
||||
#endif
|
||||
#ifdef Q_OS_UNIX
|
||||
pipe(sig_pipe);
|
||||
sig_notifier = new QSocketNotifier(sig_pipe[0], QSocketNotifier::Read, this);
|
||||
connect(sig_notifier, SIGNAL(activated(int)), SLOT(sig_activated(int)));
|
||||
unixWatchAdd(SIGINT);
|
||||
unixWatchAdd(SIGHUP);
|
||||
unixWatchAdd(SIGTERM);
|
||||
#endif
|
||||
}
|
||||
|
||||
~Private()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
if(use_handler)
|
||||
SetConsoleCtrlHandler((PHANDLER_ROUTINE)winHandler, FALSE);
|
||||
#endif
|
||||
#ifdef Q_OS_UNIX
|
||||
unixWatchRemove(SIGINT);
|
||||
unixWatchRemove(SIGHUP);
|
||||
unixWatchRemove(SIGTERM);
|
||||
delete sig_notifier;
|
||||
close(sig_pipe[0]);
|
||||
close(sig_pipe[1]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static BOOL winHandler(DWORD ctrlType)
|
||||
{
|
||||
Q_UNUSED(ctrlType);
|
||||
QMetaObject::invokeMethod(g_pq->d, "ctrl_ready", Qt::QueuedConnection);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
static void unixHandler(int sig)
|
||||
{
|
||||
Q_UNUSED(sig);
|
||||
unsigned char c = 0;
|
||||
::write(g_pq->d->sig_pipe[1], &c, 1);
|
||||
}
|
||||
|
||||
void unixWatchAdd(int sig)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigaction(sig, NULL, &sa);
|
||||
// if the signal is ignored, don't take it over. this is
|
||||
// recommended by the glibc manual
|
||||
if(sa.sa_handler == SIG_IGN)
|
||||
return;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = unixHandler;
|
||||
sigaction(sig, &sa, 0);
|
||||
}
|
||||
|
||||
void unixWatchRemove(int sig)
|
||||
{
|
||||
struct sigaction sa;
|
||||
sigaction(sig, NULL, &sa);
|
||||
// ignored means we skipped it earlier, so we should
|
||||
// skip it again
|
||||
if(sa.sa_handler == SIG_IGN)
|
||||
return;
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigaction(sig, &sa, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void ctrl_ready()
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
do_emit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void sig_activated(int)
|
||||
{
|
||||
#ifdef Q_OS_UNIX
|
||||
unsigned char c;
|
||||
::read(sig_pipe[0], &c, 1);
|
||||
do_emit();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
void do_emit()
|
||||
{
|
||||
// only signal once
|
||||
if(!done)
|
||||
{
|
||||
done = true;
|
||||
emit q->quit();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ProcessQuit::ProcessQuit(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new Private(this);
|
||||
}
|
||||
|
||||
ProcessQuit::~ProcessQuit()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ProcessQuit *ProcessQuit::instance()
|
||||
{
|
||||
QMutexLocker locker(pq_mutex());
|
||||
if(!g_pq)
|
||||
{
|
||||
g_pq = new ProcessQuit;
|
||||
g_pq->moveToThread(QCoreApplication::instance()->thread());
|
||||
#ifndef NO_IRISNET
|
||||
irisNetAddPostRoutine(cleanup);
|
||||
#endif
|
||||
}
|
||||
return g_pq;
|
||||
}
|
||||
|
||||
void ProcessQuit::reset()
|
||||
{
|
||||
QMutexLocker locker(pq_mutex());
|
||||
if(g_pq)
|
||||
g_pq->d->done = false;
|
||||
}
|
||||
|
||||
void ProcessQuit::cleanup()
|
||||
{
|
||||
delete g_pq;
|
||||
g_pq = 0;
|
||||
}
|
||||
|
||||
#ifndef NO_IRISNET
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "processquit.moc"
|
||||
109
iris-legacy/iris/irisnet/processquit.h
Normal file
109
iris-legacy/iris/irisnet/processquit.h
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Justin Karneges
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PROCESSQUIT_H
|
||||
#define PROCESSQUIT_H
|
||||
|
||||
#ifdef NO_IRISNET
|
||||
# include <QtCore>
|
||||
# define IRISNET_EXPORT
|
||||
#else
|
||||
# include "irisnetglobal.h"
|
||||
#endif
|
||||
|
||||
#ifndef NO_IRISNET
|
||||
namespace XMPP {
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Listens for termination requests
|
||||
|
||||
ProcessQuit listens for requests to terminate the application process. On Unix platforms, these are the signals SIGINT, SIGHUP, and SIGTERM. On Windows, these are the console control events for Ctrl+C, console window close, and system shutdown. For Windows GUI programs, ProcessQuit has no effect.
|
||||
|
||||
For GUI programs, ProcessQuit is not a substitute for QSessionManager. The only safe way to handle termination of a GUI program in the usual way is to use QSessionManager. However, ProcessQuit does give additional benefit to Unix GUI programs that might be terminated unconventionally, so it can't hurt to support both.
|
||||
|
||||
When a termination request is received, the application should exit gracefully, and generally without user interaction. Otherwise, it is at risk of being terminated outside of its control. For example, if a Windows console application does not exit after just a few seconds of attempting to close the console window, Windows will display a prompt to the user asking if the process should be ended immediately.
|
||||
|
||||
Using ProcessQuit is easy, and it usually amounts to a single line:
|
||||
\code
|
||||
myapp.connect(ProcessQuit::instance(), SIGNAL(quit()), SLOT(do_quit()));
|
||||
\endcode
|
||||
|
||||
Calling instance() returns a pointer to the global ProcessQuit instance, which will be created if necessary. The quit() signal is emitted when a request to terminate is received. The quit() signal is only emitted once, future termination requests are ignored. Call reset() to allow the quit() signal to be emitted again.
|
||||
*/
|
||||
class IRISNET_EXPORT ProcessQuit : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\brief Returns the global ProcessQuit instance
|
||||
|
||||
If the global instance does not exist yet, it will be created, and the termination handlers will be installed.
|
||||
|
||||
\sa cleanup
|
||||
*/
|
||||
static ProcessQuit *instance();
|
||||
|
||||
/**
|
||||
\brief Allows the quit() signal to be emitted again
|
||||
|
||||
ProcessQuit only emits the quit() signal once, so that if a user repeatedly presses Ctrl-C or sends SIGTERM, your shutdown slot will not be called multiple times. This is normally the desired behavior, but if you are ignoring the termination request then you may want to allow future notifications. Calling this function will allow the quit() signal to be emitted again, if a new termination request arrives.
|
||||
|
||||
\sa quit
|
||||
*/
|
||||
static void reset();
|
||||
|
||||
/**
|
||||
\brief Frees all resources used by ProcessQuit
|
||||
|
||||
This function will free any resources used by ProcessQuit, including the global instance, and the termination handlers will be uninstalled (reverted to default). Future termination requests will cause the application to exit abruptly.
|
||||
|
||||
\note You normally do not need to call this function directly. When IrisNet cleans up, it will be called.
|
||||
|
||||
\sa instance
|
||||
*/
|
||||
static void cleanup();
|
||||
|
||||
signals:
|
||||
/**
|
||||
\brief Notification of termination request
|
||||
|
||||
This signal is emitted when a termination request is received. It is only emitted once, unless reset() is called.
|
||||
|
||||
Upon receiving this signal, the application should proceed to exit gracefully, and generally without user interaction.
|
||||
|
||||
\sa reset
|
||||
*/
|
||||
void quit();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
friend class Private;
|
||||
Private *d;
|
||||
|
||||
ProcessQuit(QObject *parent = 0);
|
||||
~ProcessQuit();
|
||||
};
|
||||
|
||||
#ifndef NO_IRISNET
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in a new issue