nc_trans.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <d2/d2_log.h>
  15. #include <d2/nc_trans.h>
  16. namespace isc {
  17. namespace d2 {
  18. // Common transaction states
  19. const int NameChangeTransaction::READY_ST;
  20. const int NameChangeTransaction::SELECTING_FWD_SERVER_ST;
  21. const int NameChangeTransaction::SELECTING_REV_SERVER_ST;
  22. const int NameChangeTransaction::PROCESS_TRANS_OK_ST;
  23. const int NameChangeTransaction::PROCESS_TRANS_FAILED_ST;
  24. const int NameChangeTransaction::NCT_DERIVED_STATE_MIN;
  25. // Common transaction events
  26. const int NameChangeTransaction::SELECT_SERVER_EVT;
  27. const int NameChangeTransaction::SERVER_SELECTED_EVT;
  28. const int NameChangeTransaction::SERVER_IO_ERROR_EVT;
  29. const int NameChangeTransaction::NO_MORE_SERVERS_EVT;
  30. const int NameChangeTransaction::IO_COMPLETED_EVT;
  31. const int NameChangeTransaction::UPDATE_OK_EVT;
  32. const int NameChangeTransaction::UPDATE_FAILED_EVT;
  33. const int NameChangeTransaction::NCT_DERIVED_EVENT_MIN;
  34. const unsigned int NameChangeTransaction::DNS_UPDATE_DEFAULT_TIMEOUT;
  35. const unsigned int NameChangeTransaction::MAX_UPDATE_TRIES_PER_SERVER;
  36. NameChangeTransaction::
  37. NameChangeTransaction(IOServicePtr& io_service,
  38. dhcp_ddns::NameChangeRequestPtr& ncr,
  39. DdnsDomainPtr& forward_domain,
  40. DdnsDomainPtr& reverse_domain)
  41. : io_service_(io_service), ncr_(ncr), forward_domain_(forward_domain),
  42. reverse_domain_(reverse_domain), dns_client_(), dns_update_request_(),
  43. dns_update_status_(DNSClient::OTHER), dns_update_response_(),
  44. forward_change_completed_(false), reverse_change_completed_(false),
  45. current_server_list_(), current_server_(), next_server_pos_(0),
  46. update_attempts_(0) {
  47. // @todo if io_service is NULL we are multi-threading and should
  48. // instantiate our own
  49. if (!io_service_) {
  50. isc_throw(NameChangeTransactionError, "IOServicePtr cannot be null");
  51. }
  52. if (!ncr_) {
  53. isc_throw(NameChangeTransactionError,
  54. "NameChangeRequest cannot be null");
  55. }
  56. if (ncr_->isForwardChange() && !(forward_domain_)) {
  57. isc_throw(NameChangeTransactionError,
  58. "Forward change must have a forward domain");
  59. }
  60. if (ncr_->isReverseChange() && !(reverse_domain_)) {
  61. isc_throw(NameChangeTransactionError,
  62. "Reverse change must have a reverse domain");
  63. }
  64. }
  65. NameChangeTransaction::~NameChangeTransaction(){
  66. }
  67. void
  68. NameChangeTransaction::startTransaction() {
  69. startModel(READY_ST);
  70. }
  71. void
  72. NameChangeTransaction::operator()(DNSClient::Status status) {
  73. // Stow the completion status and re-enter the run loop with the event
  74. // set to indicate IO completed.
  75. // runModel is exception safe so we are good to call it here.
  76. // It won't exit until we hit the next IO wait or the state model ends.
  77. setDnsUpdateStatus(status);
  78. runModel(IO_COMPLETED_EVT);
  79. }
  80. void
  81. NameChangeTransaction::sendUpdate(bool /* use_tsig_ */) {
  82. try {
  83. ++update_attempts_;
  84. // @todo add logic to add/replace TSIG key info in request if
  85. // use_tsig_ is true. We should be able to navigate to the TSIG key
  86. // for the current server. If not we would need to add that.
  87. // @todo time out should ultimately be configurable, down to
  88. // server level?
  89. dns_client_->doUpdate(*io_service_, current_server_->getIpAddress(),
  90. current_server_->getPort(), *dns_update_request_,
  91. DNS_UPDATE_DEFAULT_TIMEOUT);
  92. // Message is on its way, so the next event should be NOP_EVT.
  93. postNextEvent(NOP_EVT);
  94. } catch (const std::exception& ex) {
  95. // We were unable to initiate the send.
  96. // It is presumed that any throw from doUpdate is due to a programmatic
  97. // error, such as an unforeseen permutation of data, rather than an IO
  98. // failure. IO errors should be caught by the underlying asiolink
  99. // mechansisms and manifested as an unsuccessful IO statu in the
  100. // DNSClient callback. Any problem here most likely means the request
  101. // is corrupt in some way and cannot be completed, therefore we will
  102. // log it and transition it to failure.
  103. LOG_ERROR(dctl_logger, DHCP_DDNS_TRANS_SEND_ERROR).arg(ex.what());
  104. transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
  105. }
  106. }
  107. void
  108. NameChangeTransaction::defineEvents() {
  109. // Call superclass impl first.
  110. StateModel::defineEvents();
  111. // Define NCT events.
  112. defineEvent(SELECT_SERVER_EVT, "SELECT_SERVER_EVT");
  113. defineEvent(SERVER_SELECTED_EVT, "SERVER_SELECTED_EVT");
  114. defineEvent(SERVER_IO_ERROR_EVT, "SERVER_IO_ERROR_EVT");
  115. defineEvent(NO_MORE_SERVERS_EVT, "NO_MORE_SERVERS_EVT");
  116. defineEvent(IO_COMPLETED_EVT, "IO_COMPLETED_EVT");
  117. defineEvent(UPDATE_OK_EVT, "UPDATE_OK_EVT");
  118. defineEvent(UPDATE_FAILED_EVT, "UPDATE_FAILED_EVT");
  119. }
  120. void
  121. NameChangeTransaction::verifyEvents() {
  122. // Call superclass impl first.
  123. StateModel::verifyEvents();
  124. // Verify NCT events.
  125. getEvent(SELECT_SERVER_EVT);
  126. getEvent(SERVER_SELECTED_EVT);
  127. getEvent(SERVER_IO_ERROR_EVT);
  128. getEvent(NO_MORE_SERVERS_EVT);
  129. getEvent(IO_COMPLETED_EVT);
  130. getEvent(UPDATE_OK_EVT);
  131. getEvent(UPDATE_FAILED_EVT);
  132. }
  133. void
  134. NameChangeTransaction::defineStates() {
  135. // Call superclass impl first.
  136. StateModel::defineStates();
  137. // This class is "abstract" in that it does not supply handlers for its
  138. // states, derivations must do that therefore they must define them.
  139. }
  140. void
  141. NameChangeTransaction::verifyStates() {
  142. // Call superclass impl first.
  143. StateModel::verifyStates();
  144. // Verify NCT states. This ensures that derivations provide the handlers.
  145. getState(READY_ST);
  146. getState(SELECTING_FWD_SERVER_ST);
  147. getState(SELECTING_REV_SERVER_ST);
  148. getState(PROCESS_TRANS_OK_ST);
  149. getState(PROCESS_TRANS_FAILED_ST);
  150. }
  151. void
  152. NameChangeTransaction::onModelFailure(const std::string& explanation) {
  153. setNcrStatus(dhcp_ddns::ST_FAILED);
  154. LOG_ERROR(dctl_logger, DHCP_DDNS_STATE_MODEL_UNEXPECTED_ERROR)
  155. .arg(explanation);
  156. }
  157. void
  158. NameChangeTransaction::retryTransition(const int server_sel_state) {
  159. if (update_attempts_ < MAX_UPDATE_TRIES_PER_SERVER) {
  160. // Re-enter the current state with same server selected.
  161. transition(getCurrState(), SERVER_SELECTED_EVT);
  162. } else {
  163. // Transition to given server selection state if we are out
  164. // of retries.
  165. transition(server_sel_state, SERVER_IO_ERROR_EVT);
  166. }
  167. }
  168. void
  169. NameChangeTransaction::setDnsUpdateRequest(D2UpdateMessagePtr& request) {
  170. dns_update_request_ = request;
  171. }
  172. void
  173. NameChangeTransaction::clearDnsUpdateRequest() {
  174. dns_update_request_.reset();
  175. }
  176. void
  177. NameChangeTransaction::setDnsUpdateStatus(const DNSClient::Status& status) {
  178. dns_update_status_ = status;
  179. }
  180. void
  181. NameChangeTransaction::setDnsUpdateResponse(D2UpdateMessagePtr& response) {
  182. dns_update_response_ = response;
  183. }
  184. void
  185. NameChangeTransaction::clearDnsUpdateResponse() {
  186. dns_update_response_.reset();
  187. }
  188. void
  189. NameChangeTransaction::setForwardChangeCompleted(const bool value) {
  190. forward_change_completed_ = value;
  191. }
  192. void
  193. NameChangeTransaction::setReverseChangeCompleted(const bool value) {
  194. reverse_change_completed_ = value;
  195. }
  196. void
  197. NameChangeTransaction::setUpdateAttempts(const size_t value) {
  198. update_attempts_ = value;
  199. }
  200. const dhcp_ddns::NameChangeRequestPtr&
  201. NameChangeTransaction::getNcr() const {
  202. return (ncr_);
  203. }
  204. const TransactionKey&
  205. NameChangeTransaction::getTransactionKey() const {
  206. return (ncr_->getDhcid());
  207. }
  208. dhcp_ddns::NameChangeStatus
  209. NameChangeTransaction::getNcrStatus() const {
  210. return (ncr_->getStatus());
  211. }
  212. DdnsDomainPtr&
  213. NameChangeTransaction::getForwardDomain() {
  214. return (forward_domain_);
  215. }
  216. DdnsDomainPtr&
  217. NameChangeTransaction::getReverseDomain() {
  218. return (reverse_domain_);
  219. }
  220. void
  221. NameChangeTransaction::initServerSelection(const DdnsDomainPtr& domain) {
  222. if (!domain) {
  223. isc_throw(NameChangeTransactionError,
  224. "initServerSelection called with an empty domain");
  225. }
  226. current_server_list_ = domain->getServers();
  227. next_server_pos_ = 0;
  228. current_server_.reset();
  229. }
  230. bool
  231. NameChangeTransaction::selectNextServer() {
  232. if ((current_server_list_) &&
  233. (next_server_pos_ < current_server_list_->size())) {
  234. current_server_ = (*current_server_list_)[next_server_pos_];
  235. dns_update_response_.reset(new
  236. D2UpdateMessage(D2UpdateMessage::INBOUND));
  237. // @todo Protocol is set on DNSClient constructor. We need
  238. // to propagate a configuration value downward, probably starting
  239. // at global, then domain, then server
  240. // Once that is supported we need to add it here.
  241. dns_client_.reset(new DNSClient(dns_update_response_ , this,
  242. DNSClient::UDP));
  243. ++next_server_pos_;
  244. return (true);
  245. }
  246. return (false);
  247. }
  248. const DNSClientPtr&
  249. NameChangeTransaction::getDNSClient() const {
  250. return (dns_client_);
  251. }
  252. const DnsServerInfoPtr&
  253. NameChangeTransaction::getCurrentServer() const {
  254. return (current_server_);
  255. }
  256. void
  257. NameChangeTransaction::setNcrStatus(const dhcp_ddns::NameChangeStatus& status) {
  258. return (ncr_->setStatus(status));
  259. }
  260. const D2UpdateMessagePtr&
  261. NameChangeTransaction::getDnsUpdateRequest() const {
  262. return (dns_update_request_);
  263. }
  264. DNSClient::Status
  265. NameChangeTransaction::getDnsUpdateStatus() const {
  266. return (dns_update_status_);
  267. }
  268. const D2UpdateMessagePtr&
  269. NameChangeTransaction::getDnsUpdateResponse() const {
  270. return (dns_update_response_);
  271. }
  272. bool
  273. NameChangeTransaction::getForwardChangeCompleted() const {
  274. return (forward_change_completed_);
  275. }
  276. bool
  277. NameChangeTransaction::getReverseChangeCompleted() const {
  278. return (reverse_change_completed_);
  279. }
  280. size_t
  281. NameChangeTransaction::getUpdateAttempts() const {
  282. return (update_attempts_);
  283. }
  284. } // namespace isc::d2
  285. } // namespace isc