[svn] commit: r1223 - in /branches/jinmei-asio: ./ src/bin/auth/ src/bin/loadzone/ src/lib/auth/ src/lib/cc/ src/lib/config/ src/lib/dns/ src/lib/dns/rdata/generic/ src/lib/dns/tests/ src/lib/python/isc/auth/ src/lib/python/isc/cc/ src/lib/python/isc/config/ src/lib/python/isc/config/unittests/
BIND 10 source code commits
bind10-changes at lists.isc.org
Tue Mar 9 02:32:46 UTC 2010
Author: jinmei
Date: Tue Mar 9 02:32:46 2010
New Revision: 1223
Log:
adapted command channel module with boost::asio. ugly hack, but works.
Added:
branches/jinmei-asio/src/lib/dns/rdata/generic/ptr_12.cc
- copied unchanged from r1210, trunk/src/lib/dns/rdata/generic/ptr_12.cc
branches/jinmei-asio/src/lib/dns/rdata/generic/ptr_12.h
- copied, changed from r1210, trunk/src/lib/dns/rdata/generic/ptr_12.h
branches/jinmei-asio/src/lib/dns/tests/rdata_ptr_unittest.cc
- copied unchanged from r1210, trunk/src/lib/dns/tests/rdata_ptr_unittest.cc
Modified:
branches/jinmei-asio/ (props changed)
branches/jinmei-asio/src/bin/auth/auth.spec
branches/jinmei-asio/src/bin/auth/auth_srv.cc
branches/jinmei-asio/src/bin/auth/auth_srv.h
branches/jinmei-asio/src/bin/auth/main.cc
branches/jinmei-asio/src/bin/loadzone/b10-loadzone.py.in
branches/jinmei-asio/src/lib/auth/Makefile.am
branches/jinmei-asio/src/lib/auth/data_source.cc
branches/jinmei-asio/src/lib/auth/data_source.h
branches/jinmei-asio/src/lib/auth/data_source_sqlite3.cc
branches/jinmei-asio/src/lib/auth/data_source_sqlite3.h
branches/jinmei-asio/src/lib/auth/data_source_sqlite3_unittest.cc
branches/jinmei-asio/src/lib/auth/data_source_static.h
branches/jinmei-asio/src/lib/auth/data_source_static_unittest.cc
branches/jinmei-asio/src/lib/auth/datasrc_unittest.cc
branches/jinmei-asio/src/lib/auth/unittest_ds.cc
branches/jinmei-asio/src/lib/auth/unittest_ds.h
branches/jinmei-asio/src/lib/cc/ (props changed)
branches/jinmei-asio/src/lib/cc/session.cc
branches/jinmei-asio/src/lib/cc/session.h
branches/jinmei-asio/src/lib/config/ccsession.cc
branches/jinmei-asio/src/lib/config/ccsession.h
branches/jinmei-asio/src/lib/dns/ (props changed)
branches/jinmei-asio/src/lib/dns/rdata/generic/rrsig_46.cc (props changed)
branches/jinmei-asio/src/lib/dns/tests/Makefile.am
branches/jinmei-asio/src/lib/python/isc/auth/master.py
branches/jinmei-asio/src/lib/python/isc/auth/sqlite3_ds.py
branches/jinmei-asio/src/lib/python/isc/cc/message.py
branches/jinmei-asio/src/lib/python/isc/config/ccsession.py
branches/jinmei-asio/src/lib/python/isc/config/cfgmgr.py
branches/jinmei-asio/src/lib/python/isc/config/unittests/ccsession_test.py
Modified: branches/jinmei-asio/src/bin/auth/auth.spec
==============================================================================
--- branches/jinmei-asio/src/bin/auth/auth.spec (original)
+++ branches/jinmei-asio/src/bin/auth/auth.spec Tue Mar 9 02:32:46 2010
@@ -4,19 +4,7 @@
"config_data": [
{ "item_name": "database_file",
"item_type": "string",
- "item_optional": False,
- "item_default": "b10-auth.db"
- },
- { "item_name": "zone_list",
- "item_type": "list",
- "item_optional": False,
- "item_default": [],
- "list_item_spec":
- { "item_name": "zone_name",
- "item_type": "string",
- "item_optional": True,
- "item_default": ""
- }
+ "item_optional": True
}
],
"commands": [
Modified: branches/jinmei-asio/src/bin/auth/auth_srv.cc
==============================================================================
--- branches/jinmei-asio/src/bin/auth/auth_srv.cc (original)
+++ branches/jinmei-asio/src/bin/auth/auth_srv.cc Tue Mar 9 02:32:46 2010
@@ -32,6 +32,8 @@
#include <dns/rrttl.h>
#include <dns/message.h>
#include <config/ccsession.h>
+#include <cc/data.h>
+#include <exceptions/exceptions.h>
#include <auth/query.h>
#include <auth/data_source.h>
@@ -65,18 +67,17 @@
};
AuthSrvImpl::AuthSrvImpl() {
- // add static data source
- data_sources.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
-
- // add SQL data source
- Sqlite3DataSrc* sd = new Sqlite3DataSrc;
- sd->init();
- data_sources.addDataSrc(ConstDataSrcPtr(sd));
}
AuthSrv::AuthSrv()
{
impl_ = new AuthSrvImpl;
+ // set empty (sqlite) data source, once ccsession is up
+ // the datasource will be set by the configuration setting
+ // (or the default one if none is set)
+ cur_datasrc_ = ConstDataSrcPtr();
+ // add static data source
+ impl_->data_sources.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
}
AuthSrv::~AuthSrv()
@@ -125,24 +126,52 @@
return (0);
}
-void
-AuthSrv::setDbFile(const std::string& db_file)
+ElementPtr
+AuthSrv::setDbFile(const isc::data::ElementPtr config)
{
- cout << "Change data source file, call our data source's function to now read " << db_file << endl;
- impl_->_db_file = db_file;
+ if (config) {
+ impl_->_db_file = config->get("database_file")->stringValue();
+ cout << "[AuthSrv] Data source database file: " << impl_->_db_file << endl;
+ }
+
+ try {
+ // create SQL data source
+ // config may be empty here; in that case it will load the default
+ // database file
+ Sqlite3DataSrc* sd = new Sqlite3DataSrc;
+ sd->init(config);
+
+ if (cur_datasrc_) {
+ impl_->data_sources.removeDataSrc(cur_datasrc_);
+ }
+
+ ConstDataSrcPtr csd = ConstDataSrcPtr(sd);
+ impl_->data_sources.addDataSrc(csd);
+ cur_datasrc_ = csd;
+
+ return isc::config::createAnswer(0);
+ } catch (isc::Exception error) {
+ cout << "[AuthSrv] error: " << error.what() << endl;
+ return isc::config::createAnswer(1, error.what());
+ }
}
ElementPtr
AuthSrv::updateConfig(isc::data::ElementPtr new_config)
{
+ ElementPtr answer = isc::config::createAnswer(0);
if (new_config) {
// the ModuleCCSession has already checked if we have
// the correct ElementPtr type as specified in our .spec file
if (new_config->contains("database_file")) {
- // We only get this if the value has actually changed.
- setDbFile(new_config->get("database_file")->stringValue());
+ answer = setDbFile(new_config);
}
}
+
+ // if we have no sqlite3 data source, use the default
+ if (!cur_datasrc_) {
+ setDbFile(ElementPtr());
+ }
- return isc::config::createAnswer(0);
+ return answer;
}
Modified: branches/jinmei-asio/src/bin/auth/auth_srv.h
==============================================================================
--- branches/jinmei-asio/src/bin/auth/auth_srv.h (original)
+++ branches/jinmei-asio/src/bin/auth/auth_srv.h Tue Mar 9 02:32:46 2010
@@ -20,6 +20,7 @@
#include <string>
#include <cc/data.h>
+#include <auth/data_source.h>
namespace isc {
namespace dns {
@@ -50,10 +51,14 @@
isc::dns::MessageRenderer& response_renderer,
bool udp_buffer);
void serve(std::string zone_name);
- void setDbFile(const std::string& db_file);
+ isc::data::ElementPtr setDbFile(const isc::data::ElementPtr config);
isc::data::ElementPtr updateConfig(isc::data::ElementPtr config);
private:
AuthSrvImpl* impl_;
+ /// We keep a pointer to the currently running sqlite datasource
+ /// so that we can specifically remove that one should the database
+ /// file change
+ isc::auth::ConstDataSrcPtr cur_datasrc_;
};
#endif // __AUTH_SRV_H
Modified: branches/jinmei-asio/src/bin/auth/main.cc
==============================================================================
--- branches/jinmei-asio/src/bin/auth/main.cc (original)
+++ branches/jinmei-asio/src/bin/auth/main.cc Tue Mar 9 02:32:46 2010
@@ -283,15 +283,13 @@
ElementPtr
my_config_handler(ElementPtr new_config)
{
- auth_server->updateConfig(new_config);
- return createAnswer(0);
+ return auth_server->updateConfig(new_config);
}
ElementPtr
my_command_handler(const string& command, const ElementPtr args) {
ElementPtr answer = createAnswer(0);
- cout << "[XX] Handle command: " << endl << command << endl;
if (command == "print_message")
{
cout << args << endl;
@@ -356,13 +354,15 @@
} else {
specfile = string(AUTH_SPECFILE_LOCATION);
}
- ModuleCCSession cs = ModuleCCSession(specfile, my_config_handler,
- my_command_handler);
// XXX: in this prototype code we'll ignore any message on the command
// channel.
boost::asio::io_service io_service;
+
+ ModuleCCSession cs(specfile, io_service, my_config_handler,
+ my_command_handler);
+
if (use_ipv4) {
udp4_server = new UDPServer(io_service, AF_INET, port);
tcp4_server = new TCPServer(io_service, AF_INET, port);
Modified: branches/jinmei-asio/src/bin/loadzone/b10-loadzone.py.in
==============================================================================
--- branches/jinmei-asio/src/bin/loadzone/b10-loadzone.py.in (original)
+++ branches/jinmei-asio/src/bin/loadzone/b10-loadzone.py.in Tue Mar 9 02:32:46 2010
@@ -16,7 +16,8 @@
import sys; sys.path.append ('@@PYTHONPATH@@')
import re, getopt
-import isc
+import isc.auth
+import isc.auth.master
#########################################################################
# usage: print usage note and exit
@@ -55,13 +56,20 @@
zonefile = args[0]
try:
- zone, zonedata = isc.auth.master.parse(zonefile, initial_origin)
+ zf = isc.auth.master.openzone(zonefile, initial_origin)
except Exception as e:
print("Error reading zone file: " + str(e))
exit(1)
try:
- isc.auth.sqlite3_ds.load(dbfile, zone, zonedata)
+ zone = isc.auth.master.zonename(zf, initial_origin)
+ except Exception as e:
+ print("Error reading zone file: " + str(e))
+ exit(1)
+
+ try:
+
+ isc.auth.sqlite3_ds.load(dbfile, zone, isc.auth.master.zonedata, zf)
except Exception as e:
print("Error loading database: " + str(e))
exit(1)
Modified: branches/jinmei-asio/src/lib/auth/Makefile.am
==============================================================================
--- branches/jinmei-asio/src/lib/auth/Makefile.am (original)
+++ branches/jinmei-asio/src/lib/auth/Makefile.am Tue Mar 9 02:32:46 2010
@@ -23,6 +23,7 @@
run_unittests_LDADD += $(SQLITE_LIBS)
run_unittests_LDADD += .libs/libauth.a
run_unittests_LDADD += $(top_builddir)/src/lib/dns/.libs/libdns.a
+run_unittests_LDADD += $(top_builddir)/src/lib/cc/libcc.a
run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/.libs/libexceptions.a
endif
Modified: branches/jinmei-asio/src/lib/auth/data_source.cc
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source.cc (original)
+++ branches/jinmei-asio/src/lib/auth/data_source.cc Tue Mar 9 02:32:46 2010
@@ -782,6 +782,19 @@
}
void
+MetaDataSrc::removeDataSrc(ConstDataSrcPtr data_src)
+{
+ std::vector<ConstDataSrcPtr>::iterator it, itr;
+ for (it = data_sources.begin(); it != data_sources.end(); it++) {
+ if (*it == data_src) {
+ itr = it;
+ }
+ }
+
+ data_sources.erase(itr);
+}
+
+void
MetaDataSrc::findClosestEnclosure(NameMatch& match, const RRClass& qclass) const
{
if (qclass == RRClass::ANY()) {
Modified: branches/jinmei-asio/src/lib/auth/data_source.h
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source.h (original)
+++ branches/jinmei-asio/src/lib/auth/data_source.h Tue Mar 9 02:32:46 2010
@@ -25,6 +25,7 @@
#include <dns/name.h>
#include <dns/rrclass.h>
+#include <cc/data.h>
namespace isc {
@@ -102,6 +103,7 @@
// Optional 'low-level' methods. These will have stub implementations
// in the general DataSrc class but MAY be overwritten by subclasses
virtual Result init() = 0;
+ virtual Result init(const isc::data::ElementPtr config) = 0;
virtual Result close() = 0;
// Mandatory 'low-level' methods: These will NOT be implemented by
@@ -181,6 +183,7 @@
void setClass(const isc::dns::RRClass& c) { rrclass = c; }
Result init() { return NOT_IMPLEMENTED; }
+ Result init(const isc::data::ElementPtr config) { return NOT_IMPLEMENTED; }
Result close() { return NOT_IMPLEMENTED; }
virtual Result findRRset(const Query& q,
@@ -245,6 +248,9 @@
//@}
void addDataSrc(ConstDataSrcPtr data_src);
+ void removeDataSrc(ConstDataSrcPtr data_src);
+ size_t dataSrcCount() { return data_sources.size(); };
+
void findClosestEnclosure(NameMatch& match,
const isc::dns::RRClass& qclass) const;
Modified: branches/jinmei-asio/src/lib/auth/data_source_sqlite3.cc
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source_sqlite3.cc (original)
+++ branches/jinmei-asio/src/lib/auth/data_source_sqlite3.cc Tue Mar 9 02:32:46 2010
@@ -487,16 +487,13 @@
}
DataSrc::Result
-Sqlite3DataSrc::init(const string& dbfile) {
- open(dbfile);
- cerr << "Schema version: " << getVersion() << endl;
-
+Sqlite3DataSrc::init(const isc::data::ElementPtr config) {
+ if (config and config->contains("database_file")) {
+ open(config->get("database_file")->stringValue());
+ } else {
+ open(DEFAULT_DB_FILE);
+ }
return (SUCCESS);
-}
-
-DataSrc::Result
-Sqlite3DataSrc::init() {
- return (init(DEFAULT_DB_FILE));
}
void
Modified: branches/jinmei-asio/src/lib/auth/data_source_sqlite3.h
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source_sqlite3.h (original)
+++ branches/jinmei-asio/src/lib/auth/data_source_sqlite3.h Tue Mar 9 02:32:46 2010
@@ -102,8 +102,8 @@
std::string& hash,
isc::dns::RRsetList& target) const;
- Result init();
- Result init(const std::string& dbfile);
+ Result init() { return init(isc::data::ElementPtr()); };
+ Result init(const isc::data::ElementPtr config);
Result close();
private:
Modified: branches/jinmei-asio/src/lib/auth/data_source_sqlite3_unittest.cc
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source_sqlite3_unittest.cc (original)
+++ branches/jinmei-asio/src/lib/auth/data_source_sqlite3_unittest.cc Tue Mar 9 02:32:46 2010
@@ -29,6 +29,7 @@
#include <dns/rrtype.h>
#include <dns/rdataclass.h>
#include <dns/rrsetlist.h>
+#include <cc/data.h>
#include "query.h"
#include "data_source.h"
@@ -38,15 +39,19 @@
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::auth;
+using namespace isc::data;
namespace {
-static const char* SQLITE_DBFILE_EXAMPLE = "testdata/test.sqlite3";
-static const char* SQLITE_DBFILE_EXAMPLE2 = "testdata/test2.sqlite3";
+static ElementPtr SQLITE_DBFILE_EXAMPLE = Element::createFromString(
+ "{ \"database_file\": \"testdata/test.sqlite3\"}");
+static ElementPtr SQLITE_DBFILE_EXAMPLE2 = Element::createFromString(
+ "{ \"database_file\": \"testdata/test2.sqlite3\"}");
// The following file must be non existent and mutt be "creatable";
// the sqlite3 library will try to create a new DB file if it doesn't exist,
// so to test a failure case the create operation should also fail.
// The "nodir", a non existent directory, is inserted for this purpose.
-static const char* SQLITE_DBFILE_NOTEXIST = "testdata/nodir/notexist";
+static ElementPtr SQLITE_DBFILE_NOTEXIST = Element::createFromString(
+ "{ \"database_file\": \"testdata/nodir/notexist\"}");
static const string sigdata_common(" 20100322084538 20100220084538 "
"33495 example.com. FAKEFAKEFAKEFAKE");
@@ -350,6 +355,7 @@
// Replace the data with a totally different zone. This should succeed,
// and shouldn't match any names in the previously managed domains.
EXPECT_EQ(DataSrc::SUCCESS, data_source.close());
+
EXPECT_EQ(DataSrc::SUCCESS, data_source.init(SQLITE_DBFILE_EXAMPLE2));
NameMatch name_match(www_name);
Modified: branches/jinmei-asio/src/lib/auth/data_source_static.h
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source_static.h (original)
+++ branches/jinmei-asio/src/lib/auth/data_source_static.h Tue Mar 9 02:32:46 2010
@@ -88,6 +88,7 @@
isc::dns::RRsetList& target) const;
Result init();
+ Result init(const isc::data::ElementPtr config) { return init(); };
Result close();
private:
StaticDataSrcImpl* impl_;
Modified: branches/jinmei-asio/src/lib/auth/data_source_static_unittest.cc
==============================================================================
--- branches/jinmei-asio/src/lib/auth/data_source_static_unittest.cc (original)
+++ branches/jinmei-asio/src/lib/auth/data_source_static_unittest.cc Tue Mar 9 02:32:46 2010
@@ -27,6 +27,7 @@
#include <dns/rrtype.h>
#include <dns/rdataclass.h>
#include <dns/rrsetlist.h>
+#include <cc/data.h>
#include "query.h"
#include "data_source.h"
Modified: branches/jinmei-asio/src/lib/auth/datasrc_unittest.cc
==============================================================================
--- branches/jinmei-asio/src/lib/auth/datasrc_unittest.cc (original)
+++ branches/jinmei-asio/src/lib/auth/datasrc_unittest.cc Tue Mar 9 02:32:46 2010
@@ -489,5 +489,15 @@
EXPECT_EQ("FHA27EURONFH5640SFJQ8MJAKMCVB7UJ", nsec3.getHash(Name("test2")));
EXPECT_EQ("A4M93LR7A60IDDQMO6TCVUPCC60CU38A", nsec3.getHash(Name("test3")));
}
-}
-
+
+TEST_F(DataSrcTest, AddRemoveDataSrc) {
+ MetaDataSrc ds;
+ ConstDataSrcPtr tsp = ConstDataSrcPtr(new TestDataSrc);
+ EXPECT_EQ(0, ds.dataSrcCount());
+ ds.addDataSrc(tsp);
+ EXPECT_EQ(1, ds.dataSrcCount());
+ ds.removeDataSrc(tsp);
+ EXPECT_EQ(0, ds.dataSrcCount());
+}
+}
+
Modified: branches/jinmei-asio/src/lib/auth/unittest_ds.cc
==============================================================================
--- branches/jinmei-asio/src/lib/auth/unittest_ds.cc (original)
+++ branches/jinmei-asio/src/lib/auth/unittest_ds.cc Tue Mar 9 02:32:46 2010
@@ -96,6 +96,12 @@
}
DataSrc::Result
+TestDataSrc::init(const isc::data::ElementPtr config)
+{
+ return init();
+}
+
+DataSrc::Result
TestDataSrc::init() {
if (initialized) {
return (SUCCESS);
Modified: branches/jinmei-asio/src/lib/auth/unittest_ds.h
==============================================================================
--- branches/jinmei-asio/src/lib/auth/unittest_ds.h (original)
+++ branches/jinmei-asio/src/lib/auth/unittest_ds.h Tue Mar 9 02:32:46 2010
@@ -92,6 +92,7 @@
isc::dns::RRsetList& target) const;
Result init();
+ Result init(const isc::data::ElementPtr config);
Result close() { return (SUCCESS); }
private:
Modified: branches/jinmei-asio/src/lib/cc/session.cc
==============================================================================
--- branches/jinmei-asio/src/lib/cc/session.cc (original)
+++ branches/jinmei-asio/src/lib/cc/session.cc Tue Mar 9 02:32:46 2010
@@ -14,44 +14,204 @@
// $Id$
-#include "data.h"
-#include "session.h"
+#include <stdint.h>
#include <cstdio>
#include <vector>
#include <iostream>
#include <sstream>
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+#include <boost/asio.hpp>
+
+#include <exceptions/exceptions.h>
+
+#include "data.h"
+#include "session.h"
+
using namespace std;
using namespace isc::cc;
using namespace isc::data;
+// some of the boost::asio names conflict with socket API system calls
+// (e.g. write(2)) so we don't import the entire boost::asio namespace.
+using boost::asio::io_service;
+using boost::asio::ip::tcp;
+
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
-Session::Session()
+namespace isc {
+namespace cc {
+
+class SessionImpl {
+public:
+ SessionImpl() : sequence_(-1) {}
+ virtual ~SessionImpl() {}
+ virtual void establish() = 0;
+ virtual int getSocket() = 0;
+ virtual void disconnect() = 0;
+ virtual void writeData(const void* data, size_t datalen) = 0;
+ virtual size_t readDataLength() = 0;
+ virtual void readData(void* data, size_t datalen) = 0;
+ virtual void startRead(boost::function<void()> user_handler) = 0;
+
+ int sequence_; // the next sequence number to use
+ std::string lname_;
+};
+
+class ASIOSession : public SessionImpl {
+public:
+ ASIOSession(io_service& io_service) :
+ io_service_(io_service), socket_(io_service_), data_length_(0)
+ {}
+ virtual void establish();
+ virtual void disconnect();
+ virtual int getSocket() { return (socket_.native()); }
+ virtual void writeData(const void* data, size_t datalen);
+ virtual size_t readDataLength();
+ virtual void readData(void* data, size_t datalen);
+ virtual void startRead(boost::function<void()> user_handler);
+private:
+ void internalRead(const boost::system::error_code& error,
+ size_t bytes_transferred);
+
+private:
+ io_service& io_service_;
+ tcp::socket socket_;
+ uint32_t data_length_;
+ boost::function<void()> user_handler_;
+ boost::system::error_code error_;
+};
+
+void
+ASIOSession::establish() {
+ socket_.connect(tcp::endpoint(boost::asio::ip::address_v4::loopback(),
+ 9912), error_);
+ if (error_) {
+ isc_throw(SessionError, "Unable to connect to message queue");
+ }
+}
+
+void
+ASIOSession::disconnect() {
+ socket_.close();
+ data_length_ = 0;
+}
+
+void
+ASIOSession::writeData(const void* data, size_t datalen) {
+ try {
+ boost::asio::write(socket_, boost::asio::buffer(data, datalen));
+ } catch (const boost::system::system_error& boost_ex) {
+ isc_throw(SessionError, "ASIO write failed: " << boost_ex.what());
+ }
+}
+
+size_t
+ASIOSession::readDataLength() {
+ size_t ret_len = data_length_;
+
+ if (ret_len == 0) {
+ readData(&data_length_, sizeof(data_length_));
+ if (data_length_ == 0) {
+ isc_throw(SessionError, "ASIO read: data length is not ready");
+ }
+ ret_len = ntohl(data_length_);
+ }
+
+ data_length_ = 0;
+ return (ret_len);
+}
+
+void
+ASIOSession::readData(void* data, size_t datalen) {
+ try {
+ boost::asio::read(socket_, boost::asio::buffer(data, datalen));
+ } catch (const boost::system::system_error& boost_ex) {
+ // to hide boost specific exceptions, we catch them explicitly
+ // and convert it to SessionError.
+ isc_throw(SessionError, "ASIO read failed: " << boost_ex.what());
+ }
+}
+
+void
+ASIOSession::startRead(boost::function<void()> user_handler) {
+ data_length_ = 0;
+ user_handler_ = user_handler;
+ async_read(socket_, boost::asio::buffer(&data_length_,
+ sizeof(data_length_)),
+ boost::bind(&ASIOSession::internalRead, this,
+ boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred));
+}
+
+void
+ASIOSession::internalRead(const boost::system::error_code& error,
+ size_t bytes_transferred)
{
- sock = -1;
- sequence = 1;
-}
-
-void
-Session::disconnect()
-{
- close(sock);
- sock = -1;
-}
-
-void
-Session::establish()
-{
- int ret;
+ if (!error) {
+ assert(bytes_transferred == sizeof(data_length_));
+ data_length_ = ntohl(data_length_);
+ if (data_length_ == 0) {
+ isc_throw(SessionError, "Invalid message length (0)");
+ }
+ user_handler_();
+ } else {
+ isc_throw(SessionError, "asynchronous read failed");
+ }
+}
+
+class SocketSession : public SessionImpl {
+public:
+ SocketSession() : sock_(-1) {}
+ virtual ~SocketSession() { disconnect(); }
+ virtual int getSocket() { return (sock_); }
+ void establish();
+ virtual void disconnect()
+ {
+ if (sock_ >= 0) {
+ close(sock_);
+ }
+ sock_ = -1;
+ }
+ virtual void writeData(const void* data, size_t datalen);
+ virtual void readData(void* data, size_t datalen);
+ virtual size_t readDataLength();
+ virtual void startRead(boost::function<void()> user_handler)
+ {} // nothing to do for this class
+private:
+ int sock_;
+};
+
+namespace { // maybe unnecessary.
+// This is a helper class to make the establish() method (below) exception-safe
+// with the RAII approach.
+class SessionHolder {
+public:
+ SessionHolder(SessionImpl* obj) : impl_obj_(obj) {}
+ ~SessionHolder()
+ {
+ if (impl_obj_ != NULL) {
+ impl_obj_->disconnect();
+ }
+ }
+ void clear() { impl_obj_ = NULL; }
+ SessionImpl* impl_obj_;
+};
+}
+
+void
+SocketSession::establish() {
+ int s;
struct sockaddr_in sin;
- sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock < -1)
- throw SessionError("socket() failed");
+ s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s < 0) {
+ isc_throw(SessionError, "socket() failed");
+ }
sin.sin_family = AF_INET;
sin.sin_port = htons(9912);
@@ -61,111 +221,138 @@
sin.sin_len = sizeof(struct sockaddr_in);
#endif
- ret = connect(sock, (struct sockaddr *)&sin, sizeof(sin));
- if (ret < 0)
- throw SessionError("Unable to connect to message queue");
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ close(s);
+ isc_throw(SessionError, "Unable to connect to message queue");
+ }
+
+ sock_ = s;
+}
+
+void
+SocketSession::writeData(const void* data, const size_t datalen) {
+ int cc = write(sock_, data, datalen);
+ if (cc != datalen) {
+ isc_throw(SessionError, "Write failed: expect " << datalen <<
+ ", actual " << cc);
+ }
+}
+
+size_t
+SocketSession::readDataLength() {
+ uint32_t length;
+ readData(&length, sizeof(length));
+ return (ntohl(length));
+}
+
+void
+SocketSession::readData(void* data, const size_t datalen) {
+ int cc = read(sock_, data, datalen);
+ if (cc != datalen) {
+ isc_throw(SessionError, "Read failed: expect " << datalen <<
+ ", actual " << cc);
+ }
+}
+
+Session::Session() : impl_(new SocketSession)
+{}
+
+Session::Session(io_service& io_service) : impl_(new ASIOSession(io_service))
+{}
+
+Session::~Session() {
+ delete impl_;
+}
+
+void
+Session::disconnect() {
+ impl_->disconnect();
+}
+
+int
+Session::getSocket() const {
+ return (impl_->getSocket());
+}
+
+void
+Session::startRead(boost::function<void()> read_callback) {
+ impl_->startRead(read_callback);
+}
+
+void
+Session::establish() {
+ impl_->establish();
+
+ // once established, encapsulate the implementation object so that we
+ // can safely release the internal resource when exception happens
+ // below.
+ SessionHolder session_holder(impl_);
//
// send a request for our local name, and wait for a response
//
- std::string get_lname_str = "{ \"type\": \"getlname\" }";
- std::stringstream get_lname_stream;
- get_lname_stream.str(get_lname_str);
- ElementPtr get_lname_msg = Element::createFromString(get_lname_stream);
+ ElementPtr get_lname_msg =
+ Element::createFromString("{ \"type\": \"getlname\" }");
sendmsg(get_lname_msg);
ElementPtr routing, msg;
recvmsg(routing, msg, false);
- lname = msg->get("lname")->stringValue();
- cout << "My local name is: " << lname << endl;
+ impl_->lname_ = msg->get("lname")->stringValue();
+ cout << "My local name is: " << impl_->lname_ << endl;
+
+ // At this point there's no risk of resource leak.
+ session_holder.clear();
}
//
// Convert to wire format and send this on the TCP stream with its length prefix
//
void
-Session::sendmsg(ElementPtr& msg)
-{
+Session::sendmsg(ElementPtr& msg) {
std::string header_wire = msg->toWire();
unsigned int length = 2 + header_wire.length();
unsigned int length_net = htonl(length);
unsigned short header_length = header_wire.length();
unsigned short header_length_net = htons(header_length);
- unsigned int ret;
-
- ret = write(sock, &length_net, 4);
- if (ret != 4)
- throw SessionError("Short write");
-
- ret = write(sock, &header_length_net, 2);
- if (ret != 2)
- throw SessionError("Short write");
-
- ret = write(sock, header_wire.c_str(), header_length);
- if (ret != header_length) {
- throw SessionError("Short write");
- }
-}
-
-void
-Session::sendmsg(ElementPtr& env, ElementPtr& msg)
-{
+
+ impl_->writeData(&length_net, sizeof(length_net));
+ impl_->writeData(&header_length_net, sizeof(header_length_net));
+ impl_->writeData(header_wire.data(), header_length);
+}
+
+void
+Session::sendmsg(ElementPtr& env, ElementPtr& msg) {
std::string header_wire = env->toWire();
std::string body_wire = msg->toWire();
unsigned int length = 2 + header_wire.length() + body_wire.length();
unsigned int length_net = htonl(length);
unsigned short header_length = header_wire.length();
unsigned short header_length_net = htons(header_length);
- unsigned int ret;
-
- ret = write(sock, &length_net, 4);
- if (ret != 4)
- throw SessionError("Short write");
-
- ret = write(sock, &header_length_net, 2);
- if (ret != 2)
- throw SessionError("Short write");
-
- ret = write(sock, header_wire.c_str(), header_length);
- if (ret != header_length) {
- throw SessionError("Short write");
- }
- ret = write(sock, body_wire.c_str(), body_wire.length());
- if (ret != body_wire.length()) {
- throw SessionError("Short write");
- }
+
+ impl_->writeData(&length_net, sizeof(length_net));
+ impl_->writeData(&header_length_net, sizeof(header_length_net));
+ impl_->writeData(header_wire.data(), header_length);
+ impl_->writeData(body_wire.data(), body_wire.length());
}
bool
-Session::recvmsg(ElementPtr& msg, bool nonblock)
-{
- unsigned int length_net;
+Session::recvmsg(ElementPtr& msg, bool nonblock) {
+ size_t length = impl_->readDataLength();
+
unsigned short header_length_net;
- unsigned int ret;
-
- ret = read(sock, &length_net, 4);
- if (ret != 4)
- throw SessionError("Short read");
-
- ret = read(sock, &header_length_net, 2);
- if (ret != 2)
- throw SessionError("Short read");
-
- unsigned int length = ntohl(length_net) - 2;
+ impl_->readData(&header_length_net, sizeof(header_length_net));
+
unsigned short header_length = ntohs(header_length_net);
if (header_length != length) {
- throw SessionError("Received non-empty body where only a header expected");
+ isc_throw(SessionError, "Length parameters invalid: total=" << length
+ << ", header=" << header_length);
}
std::vector<char> buffer(length);
- ret = read(sock, &buffer[0], length);
- if (ret != length) {
- throw SessionError("Short read");
- }
+ impl_->readData(&buffer[0], length);
std::string wire = std::string(&buffer[0], length);
-
std::stringstream wire_stream;
wire_stream << wire;
@@ -176,36 +363,26 @@
}
bool
-Session::recvmsg(ElementPtr& env, ElementPtr& msg, bool nonblock)
-{
- unsigned int length_net;
+Session::recvmsg(ElementPtr& env, ElementPtr& msg, bool nonblock) {
+ size_t length = impl_->readDataLength();
+
unsigned short header_length_net;
- unsigned int ret;
-
- ret = read(sock, &length_net, 4);
- if (ret != 4)
- throw SessionError("Short read");
-
- ret = read(sock, &header_length_net, 2);
- if (ret != 2)
- throw SessionError("Short read");
-
- unsigned int length = ntohl(length_net);
+ impl_->readData(&header_length_net, sizeof(header_length_net));
+
unsigned short header_length = ntohs(header_length_net);
- if (header_length > length)
- throw SessionError("Bad header length");
+ if (header_length > length || length < 2) {
+ isc_throw(SessionError, "Length parameters invalid: total=" << length
+ << ", header=" << header_length);
+ }
// remove the header-length bytes from the total length
length -= 2;
std::vector<char> buffer(length);
- ret = read(sock, &buffer[0], length);
- if (ret != length) {
- throw SessionError("Short read");
- }
+ impl_->readData(&buffer[0], length);
std::string header_wire = std::string(&buffer[0], header_length);
- std::string body_wire = std::string(&buffer[0] + header_length, length - header_length);
-
+ std::string body_wire = std::string(&buffer[0] + header_length,
+ length - header_length);
std::stringstream header_wire_stream;
header_wire_stream << header_wire;
env = Element::fromWire(header_wire_stream, header_length);
@@ -219,8 +396,7 @@
}
void
-Session::subscribe(std::string group, std::string instance)
-{
+Session::subscribe(std::string group, std::string instance) {
ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
env->set("type", Element::create("subscribe"));
@@ -231,8 +407,7 @@
}
void
-Session::unsubscribe(std::string group, std::string instance)
-{
+Session::unsubscribe(std::string group, std::string instance) {
ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
env->set("type", Element::create("unsubscribe"));
@@ -249,43 +424,40 @@
ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
env->set("type", Element::create("send"));
- env->set("from", Element::create(lname));
+ env->set("from", Element::create(impl_->lname_));
env->set("to", Element::create(to));
env->set("group", Element::create(group));
env->set("instance", Element::create(instance));
- env->set("seq", Element::create(sequence));
+ env->set("seq", Element::create(impl_->sequence_));
//env->set("msg", Element::create(msg->toWire()));
sendmsg(env, msg);
- return (sequence++);
+ return (++impl_->sequence_);
}
bool
-Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg, bool nonblock)
+Session::group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
+ bool nonblock)
{
- bool got_message = recvmsg(envelope, msg, nonblock);
- if (!got_message) {
- return false;
- }
-
- return (true);
+ return (recvmsg(envelope, msg, nonblock));
}
unsigned int
-Session::reply(ElementPtr& envelope, ElementPtr& newmsg)
-{
+Session::reply(ElementPtr& envelope, ElementPtr& newmsg) {
ElementPtr env = Element::create(std::map<std::string, ElementPtr>());
env->set("type", Element::create("send"));
- env->set("from", Element::create(lname));
+ env->set("from", Element::create(impl_->lname_));
env->set("to", Element::create(envelope->get("from")->stringValue()));
env->set("group", Element::create(envelope->get("group")->stringValue()));
env->set("instance", Element::create(envelope->get("instance")->stringValue()));
- env->set("seq", Element::create(sequence));
+ env->set("seq", Element::create(impl_->sequence_));
env->set("reply", Element::create(envelope->get("seq")->intValue()));
sendmsg(env, newmsg);
- return (sequence++);
-}
+ return (++impl_->sequence_);
+}
+}
+}
Modified: branches/jinmei-asio/src/lib/cc/session.h
==============================================================================
--- branches/jinmei-asio/src/lib/cc/session.h (original)
+++ branches/jinmei-asio/src/lib/cc/session.h Tue Mar 9 02:32:46 2010
@@ -18,39 +18,52 @@
#define _ISC_SESSION_H 1
#include <string>
-#include <vector>
-#include <map>
+
+#include <boost/function.hpp>
+
+#include <exceptions/exceptions.h>
#include "data.h"
+namespace boost {
+namespace asio {
+class io_service;
+}
+}
+
namespace isc {
namespace cc {
- class SessionError : public std::exception {
+ class SessionImpl;
+
+ class SessionError : public isc::Exception {
public:
- SessionError(std::string m = "CC Session Error") : msg(m) {}
- ~SessionError() throw() {}
- const char* what() const throw() { return msg.c_str(); }
- private:
- std::string msg;
+ SessionError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) {}
};
class Session {
private:
- int sock;
- int sequence; // the next sequence number to use
+ SessionImpl* impl_;
+
+ private:
+ Session(const Session& source);
+ Session& operator=(const Session& source);
public:
- std::string lname;
-
Session();
+ Session(boost::asio::io_service& ioservice);
+ ~Session();
// XXX: quick hack to allow the user to watch the socket directly.
- int getSocket() const { return (sock); }
+ int getSocket() const;
+
+ void startRead(boost::function<void()> read_callback);
void establish();
void disconnect();
void sendmsg(isc::data::ElementPtr& msg);
- void sendmsg(isc::data::ElementPtr& env, isc::data::ElementPtr& msg);
+ void sendmsg(isc::data::ElementPtr& env,
+ isc::data::ElementPtr& msg);
bool recvmsg(isc::data::ElementPtr& msg,
bool nonblock = true);
bool recvmsg(isc::data::ElementPtr& env,
Modified: branches/jinmei-asio/src/lib/config/ccsession.cc
==============================================================================
--- branches/jinmei-asio/src/lib/config/ccsession.cc (original)
+++ branches/jinmei-asio/src/lib/config/ccsession.cc Tue Mar 9 02:32:46 2010
@@ -31,6 +31,7 @@
#include <sstream>
#include <cerrno>
+#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <cc/data.h>
@@ -162,11 +163,48 @@
file.close();
}
-ModuleCCSession::ModuleCCSession(std::string spec_file_name,
- isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
- isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args)
- ) throw (isc::cc::SessionError):
- session_(isc::cc::Session())
+void
+ModuleCCSession::startCheck() {
+ // data available on the command channel. process it in the synchronous
+ // mode.
+ check_command();
+
+ // start asynchronous read again.
+ session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
+}
+
+ModuleCCSession::ModuleCCSession(
+ std::string spec_file_name,
+ boost::asio::io_service& io_service,
+ isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
+ isc::data::ElementPtr(*command_handler)(
+ const std::string& command, const isc::data::ElementPtr args)
+ ) throw (isc::cc::SessionError) :
+ session_(io_service)
+{
+ init(spec_file_name, config_handler, command_handler);
+
+ // register callback for asynchronous read
+ session_.startRead(boost::bind(&ModuleCCSession::startCheck, this));
+}
+
+ModuleCCSession::ModuleCCSession(
+ std::string spec_file_name,
+ isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
+ isc::data::ElementPtr(*command_handler)(
+ const std::string& command, const isc::data::ElementPtr args)
+ ) throw (isc::cc::SessionError)
+{
+ init(spec_file_name, config_handler, command_handler);
+}
+
+void
+ModuleCCSession::init(
+ std::string spec_file_name,
+ isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config),
+ isc::data::ElementPtr(*command_handler)(
+ const std::string& command, const isc::data::ElementPtr args)
+ ) throw (isc::cc::SessionError)
{
read_module_specification(spec_file_name);
sleep(1);
@@ -189,16 +227,24 @@
ElementPtr spec_msg = createCommand("module_spec", module_specification_.getFullSpec());
session_.group_sendmsg(spec_msg, "ConfigManager");
session_.group_recvmsg(env, answer, false);
-
+ int rcode;
+ ElementPtr err = parseAnswer(rcode, answer);
+ if (rcode != 0) {
+ std::cerr << "[" << module_name_ << "] Error in specification: " << answer << std::endl;
+ }
+
config_ = Element::createFromString("{}");
// get any stored configuration from the manager
if (config_handler_) {
ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
session_.group_sendmsg(cmd, "ConfigManager");
session_.group_recvmsg(env, answer, false);
- int rcode;
ElementPtr new_config = parseAnswer(rcode, answer);
- handleConfigUpdate(new_config);
+ if (rcode == 0) {
+ handleConfigUpdate(new_config);
+ } else {
+ std::cerr << "[" << module_name_ << "] Error getting config: " << new_config << std::endl;
+ }
}
}
Modified: branches/jinmei-asio/src/lib/config/ccsession.h
==============================================================================
--- branches/jinmei-asio/src/lib/config/ccsession.h (original)
+++ branches/jinmei-asio/src/lib/config/ccsession.h Tue Mar 9 02:32:46 2010
@@ -23,6 +23,12 @@
#include <config/module_spec.h>
#include <cc/session.h>
#include <cc/data.h>
+
+namespace boost {
+namespace asio {
+class io_service;
+}
+}
namespace isc {
namespace config {
@@ -54,6 +60,11 @@
* module specification.
*/
ModuleCCSession(std::string spec_file_name,
+ isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config) = NULL,
+ isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args) = NULL
+ ) throw (isc::cc::SessionError);
+ ModuleCCSession(std::string spec_file_name,
+ boost::asio::io_service& io_service,
isc::data::ElementPtr(*config_handler)(isc::data::ElementPtr new_config) = NULL,
isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args) = NULL
) throw (isc::cc::SessionError);
@@ -91,7 +102,15 @@
void set_command_handler(isc::data::ElementPtr(*command_handler)(const std::string& command, const isc::data::ElementPtr args)) { command_handler_ = command_handler; };
private:
+ void init(
+ std::string spec_file_name,
+ isc::data::ElementPtr(*config_handler)(
+ isc::data::ElementPtr new_config),
+ isc::data::ElementPtr(*command_handler)(
+ const std::string& command, const isc::data::ElementPtr args)
+ ) throw (isc::cc::SessionError);
void read_module_specification(const std::string& filename);
+ void startCheck();
std::string module_name_;
isc::cc::Session session_;
Modified: branches/jinmei-asio/src/lib/dns/tests/Makefile.am
==============================================================================
--- branches/jinmei-asio/src/lib/dns/tests/Makefile.am (original)
+++ branches/jinmei-asio/src/lib/dns/tests/Makefile.am Tue Mar 9 02:32:46 2010
@@ -15,7 +15,7 @@
run_unittests_SOURCES += rdata_in_a_unittest.cc rdata_in_aaaa_unittest.cc
run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc
-run_unittests_SOURCES += rdata_cname_unittest.cc
+run_unittests_SOURCES += rdata_ptr_unittest.cc rdata_cname_unittest.cc
run_unittests_SOURCES += rdata_dname_unittest.cc
run_unittests_SOURCES += rdata_opt_unittest.cc
run_unittests_SOURCES += rdata_dnskey_unittest.cc
Modified: branches/jinmei-asio/src/lib/python/isc/auth/master.py
==============================================================================
--- branches/jinmei-asio/src/lib/python/isc/auth/master.py (original)
+++ branches/jinmei-asio/src/lib/python/isc/auth/master.py Tue Mar 9 02:32:46 2010
@@ -48,15 +48,15 @@
# records: generator function to return complete RRs from the zone file,
# combining lines when necessary because of parentheses
# input:
-# zonedata as an array of lines
+# descriptor for a zone master file (returned from openzone)
# yields:
# complete RR
#########################################################################
-def records(data):
+def records(input):
record = []
complete = True
paren = 0
- for line in data:
+ for line in input:
list = cleanup(line).split()
for word in list:
if paren == 0:
@@ -230,7 +230,7 @@
m = filename.match(rest)
if m:
file = m.group(1)
- return parse(file)
+ return file
#########################################################################
# four: try parsing on the assumption that the RR type is specified in
@@ -339,28 +339,37 @@
origin=''
#########################################################################
-# do_parse: parse a zone master file and return it as an array of
-# tuples
-#########################################################################
-def do_parse(file, initial_origin = '.'):
+# openzone: open a zone master file, set initial origin, return descriptor
+#########################################################################
+def openzone(filename, initial_origin = '.'):
+ try:
+ zf = open(filename, 'r')
+ except:
+ return
+ origin = initial_origin
+ return zf
+
+#########################################################################
+# zonedata: generator function to parse a zone master file and return
+# each RR as a (name, ttl, type, class, rdata) tuple
+#########################################################################
+def zonedata(zone):
global defttl, origin, defclass
- if not origin:
- origin = initial_origin
-
- zone = []
name = ''
- data = open(file).read().splitlines()
- for record in records(data):
+ for record in records(zone):
if directive(record):
continue
incl = include(record)
if incl:
- zone += incl
+ sub = openzone(incl, origin)
+ for name, ttl, rrclass, rrtype, rdata in zonedata(sub):
+ yield (name, ttl, rrclass, rrtype, rdata)
+ sub.close()
continue
-
+
first = record.split()[0]
if first == '@':
name = origin
@@ -399,46 +408,47 @@
if (ttl == -1):
raise MasterFileError("No TTL specified; zone rejected")
- zone.append((name, ttl, rrclass, rrtype, rdata))
-
- return zone
-
-#########################################################################
-# parse: call do_parse on behalf of a caller; determine the zone name
-# and return the zone data
-# input:
-# filename
-# returns:
-# zonename, data
-#########################################################################
-def parse(file, initial_origin = '.'):
- zone = do_parse(file, initial_origin)
- zonename = ''
- for record in zone:
- if record[3].lower() == 'soa':
- zonename = record[0]
- if not zonename:
- raise MasterFileError("No SOA; zone rejected")
- return zonename, zone
+ yield (name, ttl, rrclass, rrtype, rdata)
+
+#########################################################################
+# zonename: scans zone data for an SOA record, returns its name, restores
+# the zone file to its prior state
+#########################################################################
+def zonename(zone, initial_origin = '.'):
+ global origin
+ old_origin = origin
+ origin = initial_origin
+ old_location = zone.tell()
+ zone.seek(0)
+ for name, ttl, rrclass, rrtype, rdata in zonedata(zone):
+ if rrtype.lower() == 'soa':
+ break
+ zone.seek(old_location)
+ origin = old_origin
+ if rrtype.lower() != 'soa':
+ raise MasterFileError("No SOA found")
+ return name
#########################################################################
# main: used for testing; parse a zone file and print out each record
# broken up into separate name, ttl, class, type, and rdata files
#########################################################################
def main():
- print ('---------------------')
try:
file = sys.argv[1]
except:
file = 'testfile'
- zone = parse(file)
- for name, ttl, rrclass, rrtype, rdata in zone:
+ zf = openzone(file, '.')
+ print ('zone name: ' + zonename(zf))
+ print ('---------------------')
+ for name, ttl, rrclass, rrtype, rdata in zonedata(zf):
print ('name: ' + name)
print ('ttl: ' + str(ttl))
print ('rrclass: ' + rrclass)
print ('rrtype: ' + rrtype)
print ('rdata: ' + rdata)
print ('---------------------')
+ zf.close()
# initialize
reset()
Modified: branches/jinmei-asio/src/lib/python/isc/auth/sqlite3_ds.py
==============================================================================
--- branches/jinmei-asio/src/lib/python/isc/auth/sqlite3_ds.py (original)
+++ branches/jinmei-asio/src/lib/python/isc/auth/sqlite3_ds.py Tue Mar 9 02:32:46 2010
@@ -119,9 +119,9 @@
# input:
# dbfile: the sqlite3 database fileanme
# zone: the zone origin
-# zonedata: an array of name/ttl/class/rrtype/rdata-text tuples
+# zonedata: an iterable set of name/ttl/class/rrtype/rdata-text tuples
#########################################################################
-def load(dbfile, zone, zonedata):
+def load(dbfile, zone, reader, file):
conn, cur = open(dbfile)
old_zone_id = get_zoneid(zone, cur)
@@ -129,7 +129,7 @@
cur.execute("INSERT INTO zones (name, rdclass) VALUES (?, 'IN')", [temp])
new_zone_id = cur.lastrowid
- for name, ttl, rdclass, rdtype, rdata in zonedata:
+ for name, ttl, rdclass, rdtype, rdata in reader(file):
sigtype = ''
if rdtype.lower() == 'rrsig':
sigtype = rdata.split()[0]
Modified: branches/jinmei-asio/src/lib/python/isc/cc/message.py
==============================================================================
--- branches/jinmei-asio/src/lib/python/isc/cc/message.py (original)
+++ branches/jinmei-asio/src/lib/python/isc/cc/message.py Tue Mar 9 02:32:46 2010
@@ -113,9 +113,9 @@
def _encode_bool(item):
"""Encode a boolean value into a bytearray of one byte (0=false)"""
if item:
- return b'\x01'
- else:
- return b'\x00'
+ return b'1'
+ else:
+ return b'0'
def _encode_array(item):
"""Encode an array, where each value is encoded recursively"""
@@ -203,7 +203,7 @@
return (value, data)
def _decode_bool(data):
- return data == b'0x01'
+ return data == b'1' or data == b'0x01'
def _decode_int(data):
return int(str(data, 'utf-8'))
Modified: branches/jinmei-asio/src/lib/python/isc/config/ccsession.py
==============================================================================
--- branches/jinmei-asio/src/lib/python/isc/config/ccsession.py (original)
+++ branches/jinmei-asio/src/lib/python/isc/config/ccsession.py Tue Mar 9 02:32:46 2010
@@ -148,6 +148,8 @@
self._session = cc_session
self._session.group_subscribe(self._module_name, "*")
+ self._remote_module_configs = {}
+
def start(self):
"""Send the specification for this module to the configuration
manager, and request the current non-default configuration.
@@ -183,6 +185,21 @@
cmd, arg = isc.config.ccsession.parse_command(msg)
if cmd == COMMAND_CONFIG_UPDATE:
new_config = arg
+ module_name = env['group']
+ # If the target channel was not this module
+ # it might be in the remote_module_configs
+ if module_name != self._module_name:
+ if module_name in self._remote_module_configs:
+ # no checking for validity, that's up to the
+ # module itself.
+ newc = self._remote_module_configs[module_name].get_local_config()
+ isc.cc.data.merge(newc, new_config)
+ self._remote_module_configs[module_name].set_local_config(newc)
+ print("[XX] updated remote config value: ")
+ print(newc)
+ return
+
+ # ok, so apparently this update is for us.
errors = []
if not self._config_handler:
answer = create_answer(2, self._module_name + " has no config handler")
@@ -202,7 +219,6 @@
else:
answer = create_answer(2, self._module_name + " has no command handler")
except Exception as exc:
- print("error! " + str(exc))
answer = create_answer(1, str(exc))
raise exc
if answer:
@@ -220,6 +236,47 @@
function that takes a command as defined in the .spec file
and return an answer created with create_answer()"""
self._command_handler = command_handler
+
+ def add_remote_config(self, spec_file_name):
+ """Gives access to the configuration of a different module.
+ These remote module options can at this moment only be
+ accessed through get_remote_config_value(). This function
+ also subscribes to the channel of the remote module name
+ to receive the relevant updates. It is not possible to
+ specify your own handler for this right now.
+ Returns the name of the module."""
+ module_spec = isc.config.module_spec_from_file(spec_file_name)
+ module_cfg = ConfigData(module_spec)
+ module_name = module_spec.get_module_name()
+ self._session.group_subscribe(module_name);
+
+ # Get the current config for that module now
+ self._session.group_sendmsg({ "command": [ "get_config", { "module_name": module_name } ] }, "ConfigManager")
+ answer, env = self._session.group_recvmsg(False)
+ if answer:
+ rcode, value = parse_answer(answer)
+ if rcode == 0:
+ if value != None and self.get_module_spec().validate_config(False, value):
+ module_cfg.set_local_config(value);
+
+ # all done, add it
+ self._remote_module_configs[module_name] = module_cfg
+ return module_name
+
+ def remove_remote_config(self, module_name):
+ """Removes the remote configuration access for this module"""
+ if module_name in self._remote_module_configs:
+ del self._remote_module_configs[module_name]
+
+ def get_remote_config_value(self, module_name, identifier):
+ """Returns the current setting for the given identifier at the
+ given module. If the module has not been added with
+ add_remote_config, a ModuleCCSessionError is raised"""
+ if module_name in self._remote_module_configs:
+ return self._remote_module_configs[module_name].get_value(identifier)
+ else:
+ raise ModuleCCSessionError("Remote module " + module_name +
+ " not found")
def __send_spec(self):
"""Sends the data specification to the configuration manager"""
@@ -245,6 +302,7 @@
else:
raise ModuleCCSessionError("No answer from configuration manager")
+
class UIModuleCCSession(MultiConfigData):
"""This class is used in a configuration user interface. It contains
specific functions for getting, displaying, and sending
Modified: branches/jinmei-asio/src/lib/python/isc/config/cfgmgr.py
==============================================================================
--- branches/jinmei-asio/src/lib/python/isc/config/cfgmgr.py (original)
+++ branches/jinmei-asio/src/lib/python/isc/config/cfgmgr.py Tue Mar 9 02:32:46 2010
@@ -287,7 +287,6 @@
self.config.data = old_data
answer = isc.config.ccsession.create_answer(1, " ".join(err_list))
else:
- print(cmd)
answer = isc.config.ccsession.create_answer(1, "Wrong number of arguments")
if not answer:
answer = isc.config.ccsession.create_answer(1, "No answer message from " + cmd[0])
Modified: branches/jinmei-asio/src/lib/python/isc/config/unittests/ccsession_test.py
==============================================================================
--- branches/jinmei-asio/src/lib/python/isc/config/unittests/ccsession_test.py (original)
+++ branches/jinmei-asio/src/lib/python/isc/config/unittests/ccsession_test.py Tue Mar 9 02:32:46 2010
@@ -343,6 +343,23 @@
mccs.check_command()
self.assertEqual(len(fake_session.message_queue), 0)
+ def test_remote_module(self):
+ fake_session = FakeModuleCCSession()
+ mccs = self.create_session("spec1.spec", None, None, fake_session)
+ mccs.remove_remote_config("Spec2")
+
+ self.assertRaises(ModuleCCSessionError, mccs.get_remote_config_value, "Spec2", "item1")
+
+ rmodname = mccs.add_remote_config(self.spec_file("spec2.spec"))
+ self.assertEqual("Spec2", rmodname)
+ self.assertRaises(isc.cc.data.DataNotFoundError, mccs.get_remote_config_value, rmodname, "asdf")
+ value, default = mccs.get_remote_config_value(rmodname, "item1")
+ self.assertEqual(1, value)
+ self.assertEqual(True, default)
+
+ mccs.remove_remote_config(rmodname)
+ self.assertRaises(ModuleCCSessionError, mccs.get_remote_config_value, "Spec2", "item1")
+
class fakeUIConn():
def __init__(self):
self.get_answers = {}
More information about the bind10-changes
mailing list