123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <d2/d2_log.h>
- #include <d2/nc_trans.h>
- #include <dns/rdata.h>
- namespace isc {
- namespace d2 {
- // Common transaction states
- const int NameChangeTransaction::READY_ST;
- const int NameChangeTransaction::SELECTING_FWD_SERVER_ST;
- const int NameChangeTransaction::SELECTING_REV_SERVER_ST;
- const int NameChangeTransaction::PROCESS_TRANS_OK_ST;
- const int NameChangeTransaction::PROCESS_TRANS_FAILED_ST;
- const int NameChangeTransaction::NCT_DERIVED_STATE_MIN;
- // Common transaction events
- const int NameChangeTransaction::SELECT_SERVER_EVT;
- const int NameChangeTransaction::SERVER_SELECTED_EVT;
- const int NameChangeTransaction::SERVER_IO_ERROR_EVT;
- const int NameChangeTransaction::NO_MORE_SERVERS_EVT;
- const int NameChangeTransaction::IO_COMPLETED_EVT;
- const int NameChangeTransaction::UPDATE_OK_EVT;
- const int NameChangeTransaction::UPDATE_FAILED_EVT;
- const int NameChangeTransaction::NCT_DERIVED_EVENT_MIN;
- const unsigned int NameChangeTransaction::DNS_UPDATE_DEFAULT_TIMEOUT;
- const unsigned int NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
- NameChangeTransaction::
- NameChangeTransaction(IOServicePtr& io_service,
- dhcp_ddns::NameChangeRequestPtr& ncr,
- DdnsDomainPtr& forward_domain,
- DdnsDomainPtr& reverse_domain)
- : io_service_(io_service), ncr_(ncr), forward_domain_(forward_domain),
- reverse_domain_(reverse_domain), dns_client_(), dns_update_request_(),
- dns_update_status_(DNSClient::OTHER), dns_update_response_(),
- forward_change_completed_(false), reverse_change_completed_(false),
- current_server_list_(), current_server_(), next_server_pos_(0),
- update_attempts_(0) {
- // @todo if io_service is NULL we are multi-threading and should
- // instantiate our own
- if (!io_service_) {
- isc_throw(NameChangeTransactionError, "IOServicePtr cannot be null");
- }
- if (!ncr_) {
- isc_throw(NameChangeTransactionError,
- "NameChangeRequest cannot be null");
- }
- if (ncr_->isForwardChange() && !(forward_domain_)) {
- isc_throw(NameChangeTransactionError,
- "Forward change must have a forward domain");
- }
- if (ncr_->isReverseChange() && !(reverse_domain_)) {
- isc_throw(NameChangeTransactionError,
- "Reverse change must have a reverse domain");
- }
- }
- NameChangeTransaction::~NameChangeTransaction(){
- }
- void
- NameChangeTransaction::startTransaction() {
- startModel(READY_ST);
- }
- void
- NameChangeTransaction::operator()(DNSClient::Status status) {
- // Stow the completion status and re-enter the run loop with the event
- // set to indicate IO completed.
- // runModel is exception safe so we are good to call it here.
- // It won't exit until we hit the next IO wait or the state model ends.
- setDnsUpdateStatus(status);
- runModel(IO_COMPLETED_EVT);
- }
- void
- NameChangeTransaction::sendUpdate(bool /* use_tsig_ */) {
- try {
- ++update_attempts_;
- // @todo add logic to add/replace TSIG key info in request if
- // use_tsig_ is true. We should be able to navigate to the TSIG key
- // for the current server. If not we would need to add that.
- // @todo time out should ultimately be configurable, down to
- // server level?
- dns_client_->doUpdate(*io_service_, current_server_->getIpAddress(),
- current_server_->getPort(), *dns_update_request_,
- DNS_UPDATE_DEFAULT_TIMEOUT);
- // Message is on its way, so the next event should be NOP_EVT.
- postNextEvent(NOP_EVT);
- } catch (const std::exception& ex) {
- // We were unable to initiate the send.
- // It is presumed that any throw from doUpdate is due to a programmatic
- // error, such as an unforeseen permutation of data, rather than an IO
- // failure. IO errors should be caught by the underlying asiolink
- // mechanisms and manifested as an unsuccessful IO status in the
- // DNSClient callback. Any problem here most likely means the request
- // is corrupt in some way and cannot be completed, therefore we will
- // log it and transition it to failure.
- LOG_ERROR(dctl_logger, DHCP_DDNS_TRANS_SEND_ERROR).arg(ex.what());
- transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
- }
- }
- void
- NameChangeTransaction::defineEvents() {
- // Call superclass impl first.
- StateModel::defineEvents();
- // Define NCT events.
- defineEvent(SELECT_SERVER_EVT, "SELECT_SERVER_EVT");
- defineEvent(SERVER_SELECTED_EVT, "SERVER_SELECTED_EVT");
- defineEvent(SERVER_IO_ERROR_EVT, "SERVER_IO_ERROR_EVT");
- defineEvent(NO_MORE_SERVERS_EVT, "NO_MORE_SERVERS_EVT");
- defineEvent(IO_COMPLETED_EVT, "IO_COMPLETED_EVT");
- defineEvent(UPDATE_OK_EVT, "UPDATE_OK_EVT");
- defineEvent(UPDATE_FAILED_EVT, "UPDATE_FAILED_EVT");
- }
- void
- NameChangeTransaction::verifyEvents() {
- // Call superclass impl first.
- StateModel::verifyEvents();
- // Verify NCT events.
- getEvent(SELECT_SERVER_EVT);
- getEvent(SERVER_SELECTED_EVT);
- getEvent(SERVER_IO_ERROR_EVT);
- getEvent(NO_MORE_SERVERS_EVT);
- getEvent(IO_COMPLETED_EVT);
- getEvent(UPDATE_OK_EVT);
- getEvent(UPDATE_FAILED_EVT);
- }
- void
- NameChangeTransaction::defineStates() {
- // Call superclass impl first.
- StateModel::defineStates();
- // This class is "abstract" in that it does not supply handlers for its
- // states, derivations must do that therefore they must define them.
- }
- void
- NameChangeTransaction::verifyStates() {
- // Call superclass impl first.
- StateModel::verifyStates();
- // Verify NCT states. This ensures that derivations provide the handlers.
- getState(READY_ST);
- getState(SELECTING_FWD_SERVER_ST);
- getState(SELECTING_REV_SERVER_ST);
- getState(PROCESS_TRANS_OK_ST);
- getState(PROCESS_TRANS_FAILED_ST);
- }
- void
- NameChangeTransaction::onModelFailure(const std::string& explanation) {
- setNcrStatus(dhcp_ddns::ST_FAILED);
- LOG_ERROR(dctl_logger, DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR)
- .arg(explanation);
- }
- void
- NameChangeTransaction::retryTransition(const int fail_to_state) {
- if (update_attempts_ < MAX_UPDATE_TRIES_PER_SERVER) {
- // Re-enter the current state with same server selected.
- transition(getCurrState(), SERVER_SELECTED_EVT);
- } else {
- // Transition to given fail_to_state state if we are out
- // of retries.
- transition(fail_to_state, SERVER_IO_ERROR_EVT);
- }
- }
- void
- NameChangeTransaction::setDnsUpdateRequest(D2UpdateMessagePtr& request) {
- dns_update_request_ = request;
- }
- void
- NameChangeTransaction::clearDnsUpdateRequest() {
- dns_update_request_.reset();
- }
- void
- NameChangeTransaction::setDnsUpdateStatus(const DNSClient::Status& status) {
- dns_update_status_ = status;
- }
- void
- NameChangeTransaction::setDnsUpdateResponse(D2UpdateMessagePtr& response) {
- dns_update_response_ = response;
- }
- void
- NameChangeTransaction::clearDnsUpdateResponse() {
- dns_update_response_.reset();
- }
- void
- NameChangeTransaction::setForwardChangeCompleted(const bool value) {
- forward_change_completed_ = value;
- }
- void
- NameChangeTransaction::setReverseChangeCompleted(const bool value) {
- reverse_change_completed_ = value;
- }
- void
- NameChangeTransaction::setUpdateAttempts(const size_t value) {
- update_attempts_ = value;
- }
- D2UpdateMessagePtr
- NameChangeTransaction::prepNewRequest(DdnsDomainPtr domain) {
- if (!domain) {
- isc_throw(NameChangeTransactionError,
- "prepNewRequest - domain cannot be null");
- }
- try {
- // Create a "blank" update request.
- D2UpdateMessagePtr request(new D2UpdateMessage(D2UpdateMessage::
- OUTBOUND));
- // Construct the Zone Section.
- dns::Name zone_name(domain->getName());
- request->setZone(zone_name, dns::RRClass::IN());
- return (request);
- } catch (const std::exception& ex) {
- isc_throw(NameChangeTransactionError, "Cannot create new request :"
- << ex.what());
- }
- }
- void
- NameChangeTransaction::addLeaseAddressRdata(dns::RRsetPtr& rrset) {
- if (!rrset) {
- isc_throw(NameChangeTransactionError,
- "addLeaseAddressRdata - RRset cannot cannot be null");
- }
- try {
- // Manufacture an RData from the lease address then add it to the RR.
- dns::rdata::ConstRdataPtr rdata;
- if (ncr_->isV4()) {
- rdata.reset(new dns::rdata::in::A(ncr_->getIpAddress()));
- } else {
- rdata.reset(new dns::rdata::in::AAAA(ncr_->getIpAddress()));
- }
- rrset->addRdata(rdata);
- } catch (const std::exception& ex) {
- isc_throw(NameChangeTransactionError, "Cannot add address rdata: "
- << ex.what());
- }
- }
- void
- NameChangeTransaction::addDhcidRdata(dns::RRsetPtr& rrset) {
- if (!rrset) {
- isc_throw(NameChangeTransactionError,
- "addDhcidRdata - RRset cannot cannot be null");
- }
- try {
- const std::vector<uint8_t>& ncr_dhcid = ncr_->getDhcid().getBytes();
- util::InputBuffer buffer(ncr_dhcid.data(), ncr_dhcid.size());
- dns::rdata::ConstRdataPtr rdata (new dns::rdata::in::
- DHCID(buffer, ncr_dhcid.size()));
- rrset->addRdata(rdata);
- } catch (const std::exception& ex) {
- isc_throw(NameChangeTransactionError, "Cannot add DCHID rdata: "
- << ex.what());
- }
- }
- void
- NameChangeTransaction::addPtrRdata(dns::RRsetPtr& rrset) {
- if (!rrset) {
- isc_throw(NameChangeTransactionError,
- "addPtrRdata - RRset cannot cannot be null");
- }
- try {
- dns::rdata::ConstRdataPtr rdata(new dns::rdata::generic::
- PTR(getNcr()->getFqdn()));
- rrset->addRdata(rdata);
- } catch (const std::exception& ex) {
- isc_throw(NameChangeTransactionError, "Cannot add PTR rdata: "
- << ex.what());
- }
- }
- const dhcp_ddns::NameChangeRequestPtr&
- NameChangeTransaction::getNcr() const {
- return (ncr_);
- }
- const TransactionKey&
- NameChangeTransaction::getTransactionKey() const {
- return (ncr_->getDhcid());
- }
- dhcp_ddns::NameChangeStatus
- NameChangeTransaction::getNcrStatus() const {
- return (ncr_->getStatus());
- }
- DdnsDomainPtr&
- NameChangeTransaction::getForwardDomain() {
- return (forward_domain_);
- }
- DdnsDomainPtr&
- NameChangeTransaction::getReverseDomain() {
- return (reverse_domain_);
- }
- void
- NameChangeTransaction::initServerSelection(const DdnsDomainPtr& domain) {
- if (!domain) {
- isc_throw(NameChangeTransactionError,
- "initServerSelection called with an empty domain");
- }
- current_server_list_ = domain->getServers();
- next_server_pos_ = 0;
- current_server_.reset();
- }
- bool
- NameChangeTransaction::selectNextServer() {
- if ((current_server_list_) &&
- (next_server_pos_ < current_server_list_->size())) {
- current_server_ = (*current_server_list_)[next_server_pos_];
- dns_update_response_.reset(new
- D2UpdateMessage(D2UpdateMessage::INBOUND));
- // @todo Protocol is set on DNSClient constructor. We need
- // to propagate a configuration value downward, probably starting
- // at global, then domain, then server
- // Once that is supported we need to add it here.
- dns_client_.reset(new DNSClient(dns_update_response_ , this,
- DNSClient::UDP));
- ++next_server_pos_;
- return (true);
- }
- return (false);
- }
- const DNSClientPtr&
- NameChangeTransaction::getDNSClient() const {
- return (dns_client_);
- }
- const DnsServerInfoPtr&
- NameChangeTransaction::getCurrentServer() const {
- return (current_server_);
- }
- void
- NameChangeTransaction::setNcrStatus(const dhcp_ddns::NameChangeStatus& status) {
- return (ncr_->setStatus(status));
- }
- const D2UpdateMessagePtr&
- NameChangeTransaction::getDnsUpdateRequest() const {
- return (dns_update_request_);
- }
- DNSClient::Status
- NameChangeTransaction::getDnsUpdateStatus() const {
- return (dns_update_status_);
- }
- const D2UpdateMessagePtr&
- NameChangeTransaction::getDnsUpdateResponse() const {
- return (dns_update_response_);
- }
- bool
- NameChangeTransaction::getForwardChangeCompleted() const {
- return (forward_change_completed_);
- }
- bool
- NameChangeTransaction::getReverseChangeCompleted() const {
- return (reverse_change_completed_);
- }
- size_t
- NameChangeTransaction::getUpdateAttempts() const {
- return (update_attempts_);
- }
- const dns::RRType&
- NameChangeTransaction::getAddressRRType() const {
- return (ncr_->isV4() ? dns::RRType::A() : dns::RRType::AAAA());
- }
- } // namespace isc::d2
- } // namespace isc
|