[xmppd-dev] commit r1536 - in trunk/jabberd14: . jabberd jabberd/lib resolver
mail at jabberd.org
mail at jabberd.org
Wed Sep 10 01:55:02 CEST 2008
Author: mawis
Date: Wed Sep 10 01:55:02 2008
New Revision: 1536
Log:
Started work on new resolver code that is using the lwresd
Added:
trunk/jabberd14/resolver/
trunk/jabberd14/resolver/Makefile.am
trunk/jabberd14/resolver/resolver.cc
trunk/jabberd14/resolver/resolver.h
Modified:
trunk/jabberd14/ChangeLog
trunk/jabberd14/Makefile.am
trunk/jabberd14/configure.ac
trunk/jabberd14/jabberd/instance_base.cc
trunk/jabberd14/jabberd/jabberd.h
trunk/jabberd14/jabberd/lib/jabberdlib.h
trunk/jabberd14/jabberd/lib/socket.cc
trunk/jabberd14/jabberd/mio_xml.cc
Modified: trunk/jabberd14/ChangeLog
==============================================================================
--- trunk/jabberd14/ChangeLog Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/ChangeLog Wed Sep 10 01:55:02 2008 (r1536)
@@ -1,3 +1,13 @@
+2008-09-09 Matthias Wimmer <m at tthias.eu>
+
+ * resolver/resolver.cc: started work on lwresd client resolver
+ * resolver/resolver.h: same
+ * jabberd/jabberd.h: same
+ * jabberd/instance_base.cc: same
+ * jabberd/lib/jabberdlib.h: same
+ * jabberd/lib/socket.cc: same
+ * jabberd/mio_xml.cc: sanity change
+
2008-09-08 Matthias Wimmer <m at tthias.eu>
* jsm/modules/mod_roster.cc: fix duplicate roster item problem
Modified: trunk/jabberd14/Makefile.am
==============================================================================
--- trunk/jabberd14/Makefile.am Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/Makefile.am Wed Sep 10 01:55:02 2008 (r1536)
@@ -1,7 +1,7 @@
EXTRA_DIST = UPGRADE jabber.xml.dist.in README.SQL README.karma README.config README.protocols README.filespool mysql.sql pgsql_createdb.sql xdb_postgresql.xml cacerts.pem
-SUBDIRS = jabberd dialback dnsrv jsm proxy65 pthsock xdb_file xdb_sql man po
-DIST_SUBDIRS = jabberd dialback dnsrv jsm proxy65 pthsock xdb_file xdb_sql man po
+SUBDIRS = jabberd dialback dnsrv jsm proxy65 pthsock resolver xdb_file xdb_sql man po
+DIST_SUBDIRS = jabberd dialback dnsrv jsm proxy65 pthsock resolver xdb_file xdb_sql man po
sysconf_DATA = jabber.xml.dist
Modified: trunk/jabberd14/configure.ac
==============================================================================
--- trunk/jabberd14/configure.ac Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/configure.ac Wed Sep 10 01:55:02 2008 (r1536)
@@ -397,6 +397,7 @@
man/Makefile \
proxy65/Makefile \
pthsock/Makefile \
+ resolver/Makefile \
xdb_file/Makefile \
xdb_sql/Makefile \
po/Makefile])
Modified: trunk/jabberd14/jabberd/instance_base.cc
==============================================================================
--- trunk/jabberd14/jabberd/instance_base.cc Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/jabberd/instance_base.cc Wed Sep 10 01:55:02 2008 (r1536)
@@ -196,4 +196,23 @@
logmessage instance_base::log(loglevel level) {
return logger->level(level);
}
+
+ xmlnode instance_base::get_instance_config() {
+ // search for the first child element of the service element in a different namespace
+ for(xmlnode x = xmlnode_get_firstchild(i->x); x; x = xmlnode_get_nextsibling(x)) {
+ // skip elements in the NS_JABBERD_CONFIGFILE namespace
+ if (j_strcmp(xmlnode_get_namespace(x), NS_JABBERD_CONFIGFILE) == 0)
+ continue;
+
+ // only elements
+ if (xmlnode_get_type(x) != NTYPE_TAG)
+ continue;
+
+ // we found it
+ return x;
+ }
+
+ // no configuration element found
+ return NULL;
+ }
};
Modified: trunk/jabberd14/jabberd/jabberd.h
==============================================================================
--- trunk/jabberd14/jabberd/jabberd.h Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/jabberd/jabberd.h Wed Sep 10 01:55:02 2008 (r1536)
@@ -820,6 +820,14 @@
* @return logmessage that can be used to stream message to
*/
logmessage log(loglevel level);
+
+ /**
+ * get instance's configuration
+ *
+ * @return the configuration root node of the instance, NULL if no configuration (should NOT be freed)
+ */
+ xmlnode get_instance_config();
+
private:
/**
* the instance structure the server identifies us with
Modified: trunk/jabberd14/jabberd/lib/jabberdlib.h
==============================================================================
--- trunk/jabberd14/jabberd/lib/jabberdlib.h Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/jabberd/lib/jabberdlib.h Wed Sep 10 01:55:02 2008 (r1536)
@@ -439,6 +439,7 @@
#ifndef WIN32
int make_netsocket(u_short port, char const* host, int type);
+int make_netsocket2(Glib::ustring servname, Glib::ustring nodename, int type);
struct in_addr *make_addr(char const* host);
#ifdef WITH_IPV6
struct in6_addr *make_addr_ipv6(char const* host);
Modified: trunk/jabberd14/jabberd/lib/socket.cc
==============================================================================
--- trunk/jabberd14/jabberd/lib/socket.cc Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/jabberd/lib/socket.cc Wed Sep 10 01:55:02 2008 (r1536)
@@ -36,6 +36,31 @@
*/
#include <jabberdlib.h>
+#include <iostream>
+
+/**
+ * Simple wrapper to create sockets
+ *
+ * @todo Currently servname has to be already numeric. It should be possible to provide service names that are resolved in /etc/services
+ *
+ * @param servname the service name (currently this has to be a numeric port number)
+ * @param nodename the hostname where to connect to or listen on
+ * @param type type of socket (NETSOCKET_SERVER, NETSOCKET_CLIENT, or NETSOCKET_UDP)
+ * @return file handle of the new socket (-1 or error)
+ */
+int make_netsocket2(Glib::ustring servname, Glib::ustring nodename, int type) {
+ std::istringstream servname_stream(servname);
+ int port = 0;
+
+ servname_stream >> port;
+
+ std::clog << "Parsed port: " << port << std::endl;
+
+ if (port < 1)
+ return -1;
+
+ return make_netsocket(port, nodename.c_str(), type);
+}
/**
* Simple wrapper to make socket creation easy.
@@ -43,7 +68,7 @@
* @param port port number of the socket
* @param host hostname where to connect to or listen on
* @param type type of socket (NETSOCKET_SERVER, NETSOCKET_CLIENT; or NETSOCKET_UDP)
- * @return file handle of the new socket
+ * @return file handle of the new socket (-1 or error)
*/
int make_netsocket(u_short port, char const* host, int type) {
int s, flag = 1;
@@ -59,6 +84,8 @@
/* is this a UDP socket or a TCP socket? */
socket_type = (type == NETSOCKET_UDP)?SOCK_DGRAM:SOCK_STREAM;
+ std::clog << "Socket_type: " << socket_type << std::endl;
+
bzero((void *)&sa,sizeof(sa));
#ifdef WITH_IPV6
@@ -67,9 +94,12 @@
if((s = socket(PF_INET,socket_type,0)) < 0)
#endif
return(-1);
+ std::clog << "socket: " << s << std::endl;
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&flag, sizeof(flag)) < 0)
return(-1);
+ std::clog << "setsockopt() successfull" << std::endl;
+
#ifdef WITH_IPV6
saddr = make_addr_ipv6(host);
#else
Modified: trunk/jabberd14/jabberd/mio_xml.cc
==============================================================================
--- trunk/jabberd14/jabberd/mio_xml.cc Mon Sep 8 14:51:44 2008 (r1535)
+++ trunk/jabberd14/jabberd/mio_xml.cc Wed Sep 10 01:55:02 2008 (r1536)
@@ -257,6 +257,13 @@
void _mio_xstream_cleanup(void* arg) {
mio m = static_cast<mio>(arg);
+ // reset handlers
+ if (m->parser) {
+ XML_SetElementHandler(m->parser, NULL, NULL);
+ XML_SetCharacterDataHandler(m->parser, NULL);
+ XML_SetNamespaceDeclHandler(m->parser, NULL, NULL);
+ }
+
xmlnode_free(m->stacknode);
m->stacknode = NULL;
Added: trunk/jabberd14/resolver/Makefile.am
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/jabberd14/resolver/Makefile.am Wed Sep 10 01:55:02 2008 (r1536)
@@ -0,0 +1,9 @@
+lib_LTLIBRARIES = libjabberdresolver.la
+
+noinst_HEADERS = resolver.h
+
+libjabberdresolver_la_SOURCES = resolver.cc
+libjabberdresolver_la_LIBADD = $(top_builddir)/jabberd/libjabberd.la
+libjabberdresolver_la_LDFLAGS = @LDFLAGS@ @VERSION_INFO@ -module -version-info 2:0:0
+
+INCLUDES = -I../jabberd -I../jabberd/lib
Added: trunk/jabberd14/resolver/resolver.cc
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/jabberd14/resolver/resolver.cc Wed Sep 10 01:55:02 2008 (r1536)
@@ -0,0 +1,338 @@
+/*
+ * Copyrights
+ *
+ * Copyright (c) 2008 Matthias Wimmer
+ *
+ * This file is part of jabberd14.
+ *
+ * This software is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This software 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+/**
+ * @file resolver.cc
+ * @brief This implements a resolver by accessing a lwresd
+ *
+ * This is a module for xmppd that implements a resolver that resolves DNS names by delegating the actual requests to a lwresd.
+ */
+
+#include <resolver.h>
+
+namespace xmppd {
+ namespace resolver {
+ resolver::resolver(instance i, xmlnode x) : instance_base(i, x), lwresd_socket(NULL), queue_timeout(60), lwresd_host("localhost"), lwresd_service("921") {
+ configurate();
+
+ open_lwresd_socket();
+ }
+
+ void resolver::open_lwresd_socket() {
+ log_debug2(ZONE, LOGT_IO, "opening socket: service=%s, host=%s", lwresd_service.c_str(), lwresd_host.c_str());
+ int udp_socket = make_netsocket2(lwresd_service, lwresd_host, NETSOCKET_UDP);
+
+ log_debug2(ZONE, LOGT_IO, "netsocket is on fd %i", udp_socket);
+
+ lwresd_socket = mio_new(udp_socket, mio_callback, this, MIO_CONNECT_RAW);
+ }
+
+ void resolver::mio_callback(mio m, int state, void* arg, xmlnode x, char* buffer, int bufsz) {
+ // sanity check
+ if (!arg) {
+ return;
+ }
+
+ // make everything a bit nicer and call mio_event
+ static_cast<resolver*>(arg)->mio_event(m, state, buffer ? std::string(buffer, bufsz) : std::string());
+ }
+
+ void resolver::mio_event(mio m, int state, std::string const& buffer) {
+ switch (state) {
+ case MIO_CLOSED:
+ mio_event_closed(m);
+ break;
+ case MIO_BUFFER:
+ mio_event_buffer(m, buffer);
+ break;
+ case MIO_ERROR:
+ default:
+ mio_event_error(m);
+ }
+ }
+
+ void resolver::mio_event_buffer(mio m, std::string const& buffer) {
+ // parse the result
+ std::istringstream buffer_stream(buffer);
+ xmppd::lwresc::lwresult query_result(buffer_stream);
+
+ // send the signal for this result
+ uint32_t serial = query_result.getSerial();
+ std::map<uint32_t, std::pair<time_t, sigc::signal<void, xmppd::lwresc::lwresult const&> > >::iterator result_listener = result_listeners.find(serial);
+ if (result_listener != result_listeners.end()) {
+ result_listener->second.second.emit(query_result);
+ result_listeners.erase(result_listener);
+ }
+
+ }
+
+ void resolver::mio_event_closed(mio m) {
+ }
+
+ void resolver::mio_event_error(mio m) {
+ }
+
+ std::list<resend_service> const& resolver::get_resend_services() {
+ return resend_services;
+ }
+
+ void resolver::configurate() {
+ // get the configuration
+ xmlnode config = get_instance_config();
+
+ // get and iterate the resend childs
+ xht namespaces = xhash_new(3);
+ xhash_put(namespaces, "dnsrv", const_cast<char*>(NS_JABBERD_CONFIG_DNSRV));
+ xmlnode_vector resend_elements = xmlnode_get_tags(config, "dnsrv:resend", namespaces);
+ for (xmlnode_vector::iterator p = resend_elements.begin(); p != resend_elements.end(); ++p) {
+ try {
+ resend_services.push_back(resend_service(*p));
+ } catch (std::invalid_argument) {
+ }
+ }
+
+ // get the queue timeout (time we are waiting to a DNS resolving result
+ char const* queuetimeout_attrib = xmlnode_get_attrib_ns(config, "queuetimeout", NULL);
+ if (queuetimeout_attrib) {
+ std::istringstream queuetimeout_stream(queuetimeout_attrib);
+ queuetimeout_stream >> queue_timeout;
+
+ // a timeout of less than 10 seconds does not seem to make sense
+ if (queue_timeout < 10) {
+ queue_timeout = 10;
+ }
+ } else {
+ queue_timeout = 60;
+ }
+ set_heartbeat_interval(queue_timeout);
+
+ // free temp resources
+ xhash_free(namespaces);
+ namespaces = NULL;
+ }
+
+ void resolver::send_query(xmppd::lwresc::lwquery const& query) {
+ // get binary representation of the query
+ std::ostringstream query_bin;
+ query_bin << query;
+
+ // send it
+ log_debug2(ZONE, LOGT_IO, "sending %i bytes", query_bin.str().length());
+ mio_write(lwresd_socket, NULL, query_bin.str().c_str(), query_bin.str().length());
+ }
+
+ sigc::connection resolver::register_result_callback(uint32_t serial, sigc::signal<void, xmppd::lwresc::lwresult const&>::slot_type const& callback) {
+ if (result_listeners.find(serial) == result_listeners.end()) {
+ result_listeners[serial] = std::pair<time_t, sigc::signal<void, xmppd::lwresc::lwresult const&> >(std::time(NULL), sigc::signal<void, xmppd::lwresc::lwresult const&>());
+ }
+
+ return result_listeners[serial].second.connect(callback);
+ }
+
+ resend_service::resend_service(xmlnode resend) : weight_sum(0) {
+ char const* service_attribute_value = xmlnode_get_attrib_ns(resend, "service", NULL);
+
+ // if there is a service attribute, keep it
+ if (service_attribute_value)
+ service = service_attribute_value;
+
+ // check, get and iterate partial childs
+ xht namespaces = xhash_new(3);
+ xhash_put(namespaces, "dnsrv", const_cast<char*>(NS_JABBERD_CONFIG_DNSRV));
+ xmlnode_vector partial_elements = xmlnode_get_tags(resend, "dnsrv:partial", namespaces);
+ xhash_free(namespaces);
+ namespaces = NULL;
+ for (xmlnode_vector::iterator p = partial_elements.begin(); p != partial_elements.end(); ++p) {
+ // get the weight for this partial destination
+ char const* weight_attrib = xmlnode_get_attrib_ns(*p, "weight", NULL);
+ int weight = 1;
+ if (weight_attrib) {
+ std::istringstream weight_stream(weight_attrib);
+ weight_stream >> weight;
+ }
+ if (weight < 1)
+ weight = 1;
+
+ // get the destination
+ char const* resend_dest = xmlnode_get_data(*p);
+ if (!resend_dest)
+ continue;
+ try {
+ xmppd::jabberid resend_jid(resend_dest);
+
+ // keep
+ resend_hosts.push_back(std::pair<int, xmppd::jabberid>(weight, resend_jid));
+ weight_sum += weight;
+ } catch (std::invalid_argument) {
+ continue;
+ }
+
+ }
+
+ // if there where no partial childs, use the text() child of the <resend/> element
+ if (resend_hosts.empty()) {
+ try {
+ char const* resend_dest = xmlnode_get_data(resend);
+ if (resend_dest) {
+ xmppd::jabberid resend_jid(resend_dest);
+
+ // keep
+ resend_hosts.push_back(std::pair<int, xmppd::jabberid>(1, resend_jid));
+ weight_sum++;
+ }
+ } catch (std::invalid_argument) {
+ }
+ }
+
+ // still no valid resend_hosts?
+ if (resend_hosts.empty()) {
+ throw std::invalid_argument("resend config contains no valid destination");
+ }
+ }
+
+ bool resend_service::is_explicit_service() const {
+ return service.length() > 0;
+ }
+
+ Glib::ustring const& resend_service::get_service_prefix() const {
+ return service;
+ }
+
+ result resolver::on_stanza_packet(dpacket dp) {
+ // sanity check
+ if (!dp || !dp->host)
+ return r_ERR;
+
+ // check if the packet already has been resolved (in the case of looping packets)
+ if (xmlnode_get_attrib_ns(dp->x, "ip", NULL) || xmlnode_get_attrib_ns(dp->x, "iperror", NULL)) {
+ char const* packet_type = xmlnode_get_attrib_ns(dp->x, "type", NULL);
+
+ // drop type='error', bounce everything else
+ if (packet_type && Glib::ustring(packet_type) == "error") {
+ log_warn(dp->host, "Looping DNS request. Dropped: %s", xmlnode_serialize_string(dp->x, xmppd::ns_decl_list(), 0));
+ xmlnode_free(dp->x);
+ } else {
+ deliver_fail(dp, N_("Looping DNS request. Dropped."));
+ }
+
+ return r_DONE;
+ }
+
+ // is there already a resolve request pending for this domain? Just add to queue for this resolving
+ if (pending_jobs.find(dp->host) != pending_jobs.end()) {
+ pending_jobs[dp->host]->add_packet(dp);
+ return r_DONE;
+ }
+
+ // store the packet, so that we can forward it when it has been resolved, and start resolving
+ pending_jobs[dp->host] = new resolver_job(*this, dp);
+ return r_DONE;
+ }
+
+ resolver_job::resolver_job(resolver& owner, dpacket dp) : owner(owner) {
+ // sanity check
+ if (!dp->host) {
+ throw std::invalid_argument("dpacket has no host");
+ }
+
+ // keep the packet
+ add_packet(dp);
+
+ // keep destination explicitly for faster access
+ destination = dp->host;
+
+ // get the services and resend destinations that we have to use (make copy)
+ resend_services = owner.get_resend_services();
+
+ // set current service
+ current_service = resend_services.begin();
+
+ // start resolving this service
+ start_resolving_service();
+ }
+
+ resolver_job::~resolver_job() {
+ // disconnect all signals pointing to us
+ for (std::list<sigc::connection>::iterator p = connected_signals.begin(); p != connected_signals.end(); ++p) {
+ p->disconnect();
+ }
+ }
+
+ void resolver_job::add_packet(dpacket dp) {
+ waiting_packets.push_back(dp);
+ }
+
+ void resolver_job::start_resolving_service() {
+ // reset the list of providing hosts
+ providing_hosts.erase(providing_hosts.begin(), providing_hosts.end());
+
+ // do we have a service, or do have have do plain AAAA+A queries?
+ if (current_service->is_explicit_service()) {
+ // need to do SRV lookup
+ //
+ // create query
+ std::ostringstream name_to_resolve;
+ name_to_resolve << std::string(current_service->get_service_prefix()) << "." << std::string(destination);
+
+ xmppd::lwresc::rrsetbyname query(name_to_resolve.str(), ns_c_in, ns_t_srv);
+
+ // register result callback
+ connected_signals.push_back(owner.register_result_callback(query.getSerial(), sigc::mem_fun(*this, &xmppd::resolver::resolver_job::on_srv_query_result)));
+
+ // send query
+ owner.send_query(query);
+
+ // XXX implementation needed
+ } else {
+ // no SRV lookup, just plain AAAA+A
+
+ // the hosts providing the service is just the destination on port 5269
+ // so put this in providing_hosts list
+ providing_hosts.push_back(std::pair<Glib::ustring, Glib::ustring>(destination, "5269"));
+
+ // no real SRV lookup step needed, so directly start the AAAA+A query stap
+ resolve_providing_hosts();
+ }
+ }
+
+ void resolver_job::resolve_providing_hosts() {
+ // XXX implement this method
+ }
+
+ void resolver_job::on_srv_query_result(xmppd::lwresc::lwresult const& result) {
+ }
+ }
+}
+
+/**
+ * init and register the resolver component in the server
+ *
+ * @todo care for destructing the resolver instance on shutdown
+ *
+ * @param i the jabber server's data about this instance
+ * @param x xmlnode of this instances configuration (???)
+ */
+extern "C" void resolver(instance i, xmlnode x) {
+ xmppd::resolver::resolver* ri = new xmppd::resolver::resolver(i, x);
+}
Added: trunk/jabberd14/resolver/resolver.h
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/jabberd14/resolver/resolver.h Wed Sep 10 01:55:02 2008 (r1536)
@@ -0,0 +1,300 @@
+/*
+ * Copyrights
+ *
+ * Copyright (c) 2008 Matthias Wimmer
+ *
+ * This file is part of jabberd14.
+ *
+ * This software is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This software 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <jabberd.h>
+
+namespace xmppd {
+ namespace resolver {
+
+ /**
+ * @brief a SRV service to resolve and the resend destinations
+ *
+ * This class stores the configuration for a service to resolve in DNS. Each instance
+ * of this class represent the configuration data of a single <resend/> element
+ * in the resolver configuration
+ */
+ class resend_service {
+ public:
+ /**
+ * construct a resend_service
+ *
+ * @param resend the xmlnode of the <resend/> element that should be represented by this instance
+ * @throws std::invalid_argument if configuration is not correct
+ */
+ resend_service(xmlnode resend);
+
+ /**
+ * does this represent a service lookup (or plain AAAA+A resolving?)
+ *
+ * @return true if this is for SRV lookups, false for plain AAAA+A lookup service
+ */
+ bool is_explicit_service() const;
+
+ /**
+ * get the service prefix for SRV records that have to be resolved
+ */
+ Glib::ustring const& get_service_prefix() const;
+
+ private:
+ /**
+ * the service to resolve, empty string for no service but plain AAAA/A lookups
+ */
+ Glib::ustring service;
+
+ /**
+ * the hosts to use as destination for the resend
+ */
+ std::list< std::pair<int, xmppd::jabberid> > resend_hosts;
+
+ /**
+ * weight sum of the resend_hosts
+ *
+ * the weight sum is stored for performance reasons, it is the sum of all weights in resend_hosts
+ */
+ int weight_sum;
+ };
+
+ // forward declaration
+ class resolver;
+
+ /**
+ * @brief class holding pending jobs and the packets waiting for its completition
+ *
+ * This class stores all packets for a given destination, resolves the IP address
+ * for this destination and then resends the packets to a s2s component including
+ * the resolved addresses
+ */
+ class resolver_job {
+ public:
+ /**
+ * create a new resolving job
+ *
+ * @param dp the packet resolving is started for
+ * @throws std::invalid_argument on failed sanity checks
+ */
+ resolver_job(resolver& owner, dpacket dp);
+
+ /**
+ * destructor
+ */
+ ~resolver_job();
+
+ /**
+ * add a packet that waits for the job to be completed
+ *
+ * @param dp the packet that is waiting
+ * @throws std::invalid_argument if the packet has a different destination, that what is being resolved by this job
+ */
+ void add_packet(dpacket dp);
+ private:
+ /**
+ * the destination, that is being resolved by this job
+ */
+ Glib::ustring destination;
+
+ /**
+ * the resolver instance, that is using this job
+ */
+ resolver& owner;
+
+ /**
+ * the packets that wait for the job to be completed
+ */
+ std::list<dpacket> waiting_packets;
+
+ /**
+ * copy of the service and resend configuration
+ *
+ * we make a copy as the main configuration of the resolver could get changed while this job is running
+ */
+ std::list<resend_service> resend_services;
+
+ /**
+ * the service that is currently resolved
+ */
+ std::list<resend_service>::const_iterator current_service;
+
+ /**
+ * start resolving of a service
+ *
+ * this starts resolving of the service current_service points to
+ */
+ void start_resolving_service();
+
+ /**
+ * list storing the result of the SRV lookup step
+ *
+ * first element in pair is the host, second element is the service (port)
+ */
+ std::list< std::pair<Glib::ustring, Glib::ustring> > providing_hosts;
+
+ /**
+ * do AAAA and A lookups for the hosts in providing_hosts
+ *
+ * This gets called after providing_hosts has been filled, either explicitly
+ * with destination and port 5269 if there was no SRV records to resolve, or
+ * by the result of a SRV lookup.
+ */
+ void resolve_providing_hosts();
+
+ /**
+ * list of signals to disconnect on destruction
+ */
+ std::list<sigc::connection> connected_signals;
+
+ /**
+ * handle results of SRV queries to the DNS
+ */
+ void on_srv_query_result(xmppd::lwresc::lwresult const& result);
+ };
+
+ /**
+ * @brief resolver component implementation
+ *
+ * This class implements a component to the xmppd that does the resolving for the server.
+ * The component implements the XMPP/xmppd specific tasks and delegates the actual resolving
+ * to an instance of lwresd (which has to be installed and configured separately.
+ */
+ class resolver : public instance_base {
+ public:
+ /**
+ * construct a resolver instance
+ *
+ * @param i the ::instance to construct a resolver for
+ * @param x the configuration element that caused the instance to be created
+ */
+ resolver(instance i, xmlnode x);
+
+ /**
+ * get the list of services and resend destinations
+ *
+ * @return the list of services to resolve and there resend destinations
+ */
+ std::list<resend_service> const& get_resend_services();
+
+ /**
+ * sends a query to the lwresd
+ *
+ * @param query the query to send
+ */
+ void send_query(xmppd::lwresc::lwquery const& query);
+
+ /**
+ * registers a callback function for query results
+ */
+ sigc::connection register_result_callback(uint32_t serial, sigc::signal<void, xmppd::lwresc::lwresult const&>::slot_type const& callback);
+
+ private:
+ /**
+ * handle received stanzas
+ *
+ * @param dp the stanza to handle
+ * @return r_DONE when handled, r_ERR on error
+ */
+ result on_stanza_packet(dpacket dp);
+
+ /**
+ * create socket for lwresd access
+ */
+ void open_lwresd_socket();
+
+ /**
+ * callback for mio events
+ *
+ * @param m the mio that called the event
+ * @param state the state that is signaled by this event
+ * @param arg the resolver instance this event is for
+ * @param x unused here
+ * @param buffer possibly received data (depending on state)
+ * @param bufsz size of the received data
+ */
+ static void mio_callback(mio m, int state, void* arg, xmlnode x, char* buffer, int bufsz);
+
+ /**
+ * handler for mio events
+ */
+ void mio_event(mio m, int state, std::string const& buffer);
+
+ /**
+ * handler for MIO_BUFFER event
+ */
+ void mio_event_buffer(mio m, std::string const& buffer);
+
+ /**
+ * handler for MIO_CLOSED event
+ */
+ void mio_event_closed(mio m);
+
+ /**
+ * handler for MIO_ERROR event
+ */
+ void mio_event_error(mio m);
+
+ /**
+ * mio wrapped socket to the lwresd
+ */
+ mio lwresd_socket;
+
+ /**
+ * load configuration
+ */
+ void configurate();
+
+ /**
+ * the services to be tried for resolving and the resend destinations for them
+ */
+ std::list<resend_service> resend_services;
+
+ /**
+ * resolving timeout
+ *
+ * time to wait at least (in seconds) for a resolving result)
+ */
+ int queue_timeout;
+
+ /**
+ * host lwresd is running on
+ */
+ Glib::ustring lwresd_host;
+
+ /**
+ * service lwresd is running as (i.e. port)
+ */
+ Glib::ustring lwresd_service;
+
+ /**
+ * the jobs currently being executed (resolving in progress) including the packets that are waiting for the completition
+ */
+ xmppd::xhash< xmppd::pointer<resolver_job> > pending_jobs;
+
+ /**
+ * map containing the listeners for resolver results
+ *
+ * the key is the query serial which will be in the result
+ * the value is a pair of the query time (for expiring) and the signal
+ */
+ std::map<uint32_t, std::pair<time_t, sigc::signal<void, xmppd::lwresc::lwresult const&> > > result_listeners;
+ };
+ }
+}
More information about the dev
mailing list