portconfig.cc 7.21 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2011  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.

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
23

#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
24
25
26

using namespace std;
using namespace isc::data;
27
28
using namespace isc::asiolink;
using namespace isc::asiodns;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

namespace isc {
namespace server_common {
namespace portconfig {

AddressList
parseAddresses(isc::data::ConstElementPtr addresses,
               const std::string& elemName)
{
    AddressList result;
    if (addresses) {
        if (addresses->getType() == Element::list) {
            for (size_t i(0); i < addresses->size(); ++ i) {
                ConstElementPtr addrPair(addresses->get(i));
                ConstElementPtr addr(addrPair->get("address"));
                ConstElementPtr port(addrPair->get("port"));
                if (!addr || ! port) {
46
                    LOG_ERROR(logger, SRVCOMM_ADDRESS_MISSING).
47
                        arg(addrPair->str());
48
49
50
51
                    isc_throw(BadValue, "Address must contain both the IP"
                        "address and port");
                }
                try {
52
53
                    // Just check, don't use the address for anything yet
                    // cppcheck-suppress unusedScopedObject
54
55
56
                    IOAddress(addr->stringValue());
                    if (port->intValue() < 0 ||
                        port->intValue() > 0xffff) {
57
                        LOG_ERROR(logger, SRVCOMM_PORT_RANGE).
58
                            arg(port->intValue()).arg(addrPair->str());
59
60
61
62
63
                        isc_throw(BadValue, "Bad port value (" <<
                            port->intValue() << ")");
                    }
                    result.push_back(AddressPair(addr->stringValue(),
                        port->intValue()));
64
                } catch (const TypeError&) { // Better error message
65
                    LOG_ERROR(logger, SRVCOMM_ADDRESS_TYPE).
66
                        arg(addrPair->str());
67
68
69
70
71
                    isc_throw(TypeError,
                        "Address must be a string and port an integer");
                }
            }
        } else if (addresses->getType() != Element::null) {
72
            LOG_ERROR(logger, SRVCOMM_ADDRESSES_NOT_LIST).arg(elemName);
73
74
75
76
77
78
            isc_throw(TypeError, elemName + " config element must be a list");
        }
    }
    return (result);
}

79
80
namespace {

81
82
vector<string> current_sockets;

83
void
84
85
86
setAddresses(DNSServiceBase& service, const AddressList& addresses,
             DNSService::ServerFlag server_options)
{
87
    service.clearServers();
88
89
90
91
    BOOST_FOREACH(const string& token, current_sockets) {
        socketRequestor().releaseSocket(token);
    }
    current_sockets.clear();
92
    BOOST_FOREACH(const AddressPair &address, addresses) {
93
        const int af(IOAddress(address.first).getFamily());
94
95
        // We use the application name supplied to the socket requestor on
        // creation. So we can freely use the SHARE_SAME
96
97
98
        const SocketRequestor::SocketID
            tcp(socketRequestor().requestSocket(SocketRequestor::TCP,
                                                address.first, address.second,
99
                                                SocketRequestor::SHARE_SAME));
100
        current_sockets.push_back(tcp.second);
101
        service.addServerTCPFromFD(tcp.first, af);
102
103
104
        const SocketRequestor::SocketID
            udp(socketRequestor().requestSocket(SocketRequestor::UDP,
                                                address.first, address.second,
105
                                                SocketRequestor::SHARE_SAME));
106
        current_sockets.push_back(udp.second);
107
        service.addServerUDPFromFD(udp.first, af, server_options);
108
109
110
111
112
    }
}

}

113
void
114
115
116
117
installListenAddresses(const AddressList& new_addresses,
                       AddressList& address_store,
                       DNSServiceBase& service,
                       DNSService::ServerFlag server_options)
118
119
{
    try {
120
        LOG_DEBUG(logger, DBG_TRACE_BASIC, SRVCOMM_SET_LISTEN);
121
        BOOST_FOREACH(const AddressPair& addr, new_addresses) {
122
123
124
125
126
127
            string addr_str;
            if (addr.first.find(':') != string::npos) {
                addr_str = "[" + addr.first + "]";
            } else {
                addr_str = addr.first;
            }
128
            LOG_DEBUG(logger, DBG_TRACE_VALUES, SRVCOMM_ADDRESS_VALUE).
129
                arg(addr_str).arg(addr.second);
130
        }
131
132
        setAddresses(service, new_addresses, server_options);
        address_store = new_addresses;
133
    } catch (const SocketRequestor::NonFatalSocketError& e) {
134
        /*
135
136
137
138
139
         * If one of the addresses isn't set successfully, we will restore
         * the old addresses, the behavior is that either all address are
         * set successuflly or none of them will be used. whether this
         * behavior is user desired, maybe we need revisited it later. And
         * if address setting is more smarter, it should check whether some
140
         * part of the new address already in used to avoid interrupting the
141
         * service.
142
         *
143
144
145
         * If the address setting still failed, we can live with it, since
         * user will get error info, command control can be used to set new
         * address. So we just catch the exception without propagating outside
146
         */
147
        LOG_ERROR(logger, SRVCOMM_ADDRESS_FAIL).arg(e.what());
148
        try {
149
            setAddresses(service, address_store, server_options);
150
        } catch (const SocketRequestor::NonFatalSocketError& e2) {
151
            LOG_FATAL(logger, SRVCOMM_ADDRESS_UNRECOVERABLE).arg(e2.what());
152
            // If we can't set the new ones, nor the old ones, at least
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
153
154
            // releasing everything should work. If it doesn't, there isn't
            // anything else we could do.
155
156
            setAddresses(service, AddressList(), server_options);
            address_store.clear();
157
        }
158
159
160
        //Anyway the new configure has problem, we need to notify configure
        //manager the new configure doesn't work
        throw;
161
    } catch (const exception& e) {
162
        // Any other kind of exception is fatal. It might mean we are in
163
        // inconsistent state with the b10-init/socket creator, so we abort
164
165
166
        // to make sure it doesn't last.
        LOG_FATAL(logger, SRVCOMM_EXCEPTION_ALLOC).arg(e.what());
        abort();
167
    } catch (...) {
168
169
170
171
        // As the previous one, but we know even less info
        LOG_FATAL(logger, SRVCOMM_UNKNOWN_EXCEPTION_ALLOC);
        abort();
    }
172
}
173

174
175
176
}
}
}