[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 &lt;resend/&gt; element
+	 * in the resolver configuration
+	 */
+	class resend_service {
+	    public:
+		/**
+		 * construct a resend_service
+		 *
+		 * @param resend the xmlnode of the &lt;resend/&gt; 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