portconfig.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // Copyright (C) 2011 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 <server_common/portconfig.h>
  15. #include <server_common/logger.h>
  16. #include <server_common/socket_request.h>
  17. #include <asiolink/io_address.h>
  18. #include <asiodns/dns_service.h>
  19. #include <boost/foreach.hpp>
  20. #include <boost/lexical_cast.hpp>
  21. using namespace std;
  22. using namespace isc::data;
  23. using namespace isc::asiolink;
  24. using namespace isc::asiodns;
  25. namespace isc {
  26. namespace server_common {
  27. namespace portconfig {
  28. AddressList
  29. parseAddresses(isc::data::ConstElementPtr addresses,
  30. const std::string& elemName)
  31. {
  32. AddressList result;
  33. if (addresses) {
  34. if (addresses->getType() == Element::list) {
  35. for (size_t i(0); i < addresses->size(); ++ i) {
  36. ConstElementPtr addrPair(addresses->get(i));
  37. ConstElementPtr addr(addrPair->get("address"));
  38. ConstElementPtr port(addrPair->get("port"));
  39. if (!addr || ! port) {
  40. LOG_ERROR(logger, SRVCOMM_ADDRESS_MISSING).
  41. arg(addrPair->str());
  42. isc_throw(BadValue, "Address must contain both the IP"
  43. "address and port");
  44. }
  45. try {
  46. IOAddress(addr->stringValue());
  47. if (port->intValue() < 0 ||
  48. port->intValue() > 0xffff) {
  49. LOG_ERROR(logger, SRVCOMM_PORT_RANGE).
  50. arg(port->intValue()).arg(addrPair->str());
  51. isc_throw(BadValue, "Bad port value (" <<
  52. port->intValue() << ")");
  53. }
  54. result.push_back(AddressPair(addr->stringValue(),
  55. port->intValue()));
  56. } catch (const TypeError&) { // Better error message
  57. LOG_ERROR(logger, SRVCOMM_ADDRESS_TYPE).
  58. arg(addrPair->str());
  59. isc_throw(TypeError,
  60. "Address must be a string and port an integer");
  61. }
  62. }
  63. } else if (addresses->getType() != Element::null) {
  64. LOG_ERROR(logger, SRVCOMM_ADDRESSES_NOT_LIST).arg(elemName);
  65. isc_throw(TypeError, elemName + " config element must be a list");
  66. }
  67. }
  68. return (result);
  69. }
  70. namespace {
  71. vector<string> current_sockets;
  72. void
  73. setAddresses(DNSServiceBase& service, const AddressList& addresses,
  74. DNSService::ServerFlag server_options)
  75. {
  76. service.clearServers();
  77. BOOST_FOREACH(const string& token, current_sockets) {
  78. socketRequestor().releaseSocket(token);
  79. }
  80. current_sockets.clear();
  81. BOOST_FOREACH(const AddressPair &address, addresses) {
  82. const int af(IOAddress(address.first).getFamily());
  83. // We use the application name supplied to the socket requestor on
  84. // creation. So we can freely use the SHARE_SAME
  85. const SocketRequestor::SocketID
  86. tcp(socketRequestor().requestSocket(SocketRequestor::TCP,
  87. address.first, address.second,
  88. SocketRequestor::SHARE_SAME));
  89. current_sockets.push_back(tcp.second);
  90. service.addServerTCPFromFD(tcp.first, af);
  91. const SocketRequestor::SocketID
  92. udp(socketRequestor().requestSocket(SocketRequestor::UDP,
  93. address.first, address.second,
  94. SocketRequestor::SHARE_SAME));
  95. current_sockets.push_back(udp.second);
  96. service.addServerUDPFromFD(udp.first, af, server_options);
  97. }
  98. }
  99. }
  100. void
  101. installListenAddresses(const AddressList& new_addresses,
  102. AddressList& address_store,
  103. DNSServiceBase& service,
  104. DNSService::ServerFlag server_options)
  105. {
  106. try {
  107. LOG_DEBUG(logger, DBG_TRACE_BASIC, SRVCOMM_SET_LISTEN);
  108. BOOST_FOREACH(const AddressPair& addr, new_addresses) {
  109. LOG_DEBUG(logger, DBG_TRACE_VALUES, SRVCOMM_ADDRESS_VALUE).
  110. arg(addr.first).arg(addr.second);
  111. }
  112. setAddresses(service, new_addresses, server_options);
  113. address_store = new_addresses;
  114. } catch (const SocketRequestor::NonFatalSocketError& e) {
  115. /*
  116. * If one of the addresses isn't set successfully, we will restore
  117. * the old addresses, the behavior is that either all address are
  118. * set successuflly or none of them will be used. whether this
  119. * behavior is user desired, maybe we need revisited it later. And
  120. * if address setting is more smarter, it should check whether some
  121. * part of the new address already in used to avoid interuption the
  122. * service.
  123. *
  124. * If the address setting still failed, we can live with it, since
  125. * user will get error info, command control can be used to set new
  126. * address. So we just catch the exception without propagating outside
  127. */
  128. LOG_ERROR(logger, SRVCOMM_ADDRESS_FAIL).arg(e.what());
  129. try {
  130. setAddresses(service, address_store, server_options);
  131. } catch (const SocketRequestor::NonFatalSocketError& e2) {
  132. LOG_FATAL(logger, SRVCOMM_ADDRESS_UNRECOVERABLE).arg(e2.what());
  133. // If we can't set the new ones, nor the old ones, at least
  134. // releasing everything should work. If it doesn't, there isn't
  135. // anything else we could do.
  136. setAddresses(service, AddressList(), server_options);
  137. address_store.clear();
  138. }
  139. //Anyway the new configure has problem, we need to notify configure
  140. //manager the new configure doesn't work
  141. throw;
  142. } catch (const exception& e) {
  143. // Any other kind of exception is fatal. It might mean we are in
  144. // inconsistent state with the boss/socket creator, so we abort
  145. // to make sure it doesn't last.
  146. LOG_FATAL(logger, SRVCOMM_EXCEPTION_ALLOC).arg(e.what());
  147. abort();
  148. } catch (...) {
  149. // As the previous one, but we know even less info
  150. LOG_FATAL(logger, SRVCOMM_UNKNOWN_EXCEPTION_ALLOC);
  151. abort();
  152. }
  153. }
  154. }
  155. }
  156. }