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