main.cc 8.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// Copyright (C) 2009  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.

// $Id$

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
Jeremy C. Reed's avatar
Jeremy C. Reed committed
21
#include <netinet/in.h>
22
#include <stdlib.h>
23
#include <errno.h>
24

25
#include <cassert>
26 27 28
#include <iostream>

#include <boost/foreach.hpp>
29
#include <boost/bind.hpp>
30 31

#include <exceptions/exceptions.h>
32

33 34
#include <dns/buffer.h>
#include <dns/message.h>
35
#include <dns/messagerenderer.h>
36

37 38 39
#include <cc/session.h>
#include <cc/data.h>
#include <config/ccsession.h>
40

41 42
#include <xfr/xfrout_client.h>

43 44
#include <auth/spec_config.h>
#include <auth/common.h>
JINMEI Tatuya's avatar
JINMEI Tatuya committed
45
#include <auth/change_user.h>
46 47
#include <auth/auth_srv.h>
#include <auth/asio_link.h>
48 49

using namespace std;
50 51 52
using namespace isc::data;
using namespace isc::cc;
using namespace isc::config;
53
using namespace isc::dns;
54
using namespace isc::xfr;
55

56 57
namespace {

JINMEI Tatuya's avatar
JINMEI Tatuya committed
58 59
bool verbose_mode = false;

60
const string PROGRAM = "Auth";
61
const char* DNSPORT = "5300";
62

63 64 65 66
// Note: this value must be greater than 0.
// TODO: make it configurable via command channel.
const uint32_t STATS_SEND_INTERVAL_SEC = 60;

67 68 69
/* need global var for config/command handlers.
 * todo: turn this around, and put handlers in the authserver
 * class itself? */
70
AuthSrv *auth_server;
71

72
asio_link::IOService* io_service;
73

74 75
ConstElementPtr
my_config_handler(ConstElementPtr new_config) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
76
    return (auth_server->updateConfig(new_config));
77 78
}

79 80 81
ConstElementPtr
my_command_handler(const string& command, ConstElementPtr args) {
    ConstElementPtr answer = createAnswer();
82

83
    if (command == "print_message") {
84 85
        cout << args << endl;
        /* let's add that message to our answer as well */
86
        answer = createAnswer(0, args);
87
    } else if (command == "shutdown") {
88
        io_service->stop();
89 90 91 92
    } else if (command == "sendstats") {
        if (verbose_mode) {
            cerr << "[b10-auth] command 'sendstats' received" << endl;
        }
93 94
        assert(auth_server != NULL);
        auth_server->submitStatistics();
95
    }
96
    
JINMEI Tatuya's avatar
JINMEI Tatuya committed
97
    return (answer);
98 99
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
100
void
101
usage() {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
102
    cerr << "Usage: b10-auth [-a address] [-p port] [-4|-6] [-nv]" << endl;
103
    exit(1);
104
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
105
} // end of anonymous namespace
106

107 108 109 110 111 112
void
statisticsTimerCallback(AuthSrv* auth_server) {
    assert(auth_server != NULL);
    auth_server->submitStatistics();
}

113 114 115
int
main(int argc, char* argv[]) {
    int ch;
116
    const char* port = DNSPORT;
Evan Hunt's avatar
Evan Hunt committed
117
    const char* address = NULL;
118
    const char* uid = NULL;
Evan Hunt's avatar
Evan Hunt committed
119
    bool use_ipv4 = true, use_ipv6 = true, cache = true;
120

121
    while ((ch = getopt(argc, argv, "46a:np:u:v")) != -1) {
122
        switch (ch) {
123
        case '4':
124 125 126 127 128
            // Note that -4 means "ipv4 only", we need to set "use_ipv6" here,
            // not "use_ipv4".  We could use something like "ipv4_only", but
            // we found the negatively named variable could confuse the code
            // logic.
            use_ipv6 = false;
129 130
            break;
        case '6':
131 132
            // The same note as -4 applies.
            use_ipv4 = false;
133
            break;
Evan Hunt's avatar
Evan Hunt committed
134 135 136
        case 'n':
            cache = false;
            break;
Evan Hunt's avatar
Evan Hunt committed
137 138 139
        case 'a':
            address = optarg;
            break;
140
        case 'p':
141
            port = optarg;
142
            break;
143 144 145
        case 'u':
            uid = optarg;
            break;
146 147 148
        case 'v':
            verbose_mode = true;
            break;
149 150 151 152 153 154
        case '?':
        default:
            usage();
        }
    }

155
    if (argc - optind > 0) {
156
        usage();
157 158
    }

159
    if (!use_ipv4 && !use_ipv6) {
160
        cerr << "[b10-auth] Error: -4 and -6 can't coexist" << endl;
161 162 163
        usage();
    }

164 165 166 167 168
    if ((!use_ipv4 || !use_ipv6) && address != NULL) {
        cerr << "[b10-auth] Error: -4|-6 and -a can't coexist" << endl;
        usage();
    }

169
    int ret = 0;
170

171
    // XXX: we should eventually pass io_service here.
JINMEI Tatuya's avatar
JINMEI Tatuya committed
172
    Session* cc_session = NULL;
173
    Session* xfrin_session = NULL;
174 175
    Session* stats_session = NULL;
    asio_link::IntervalTimer* itimer = NULL;
176
    bool xfrin_session_established = false; // XXX (see Trac #287)
177
    bool stats_session_established = false; // XXX (see Trac #287)
178
    ModuleCCSession* config_session = NULL;
179 180 181 182 183 184 185
    string xfrout_socket_path;
    if (getenv("B10_FROM_BUILD") != NULL) {
        xfrout_socket_path = string(getenv("B10_FROM_BUILD")) + "/auth_xfrout_conn";
    } else {
        xfrout_socket_path = UNIX_SOCKET_FILE;
    }
    XfroutClient xfrout_client(xfrout_socket_path);
186
    try {
187
        string specfile;
188 189
        if (getenv("B10_FROM_BUILD")) {
            specfile = string(getenv("B10_FROM_BUILD")) +
190
                "/src/bin/auth/auth.spec";
191
        } else {
192
            specfile = string(AUTH_SPECFILE_LOCATION);
193
        }
194

195
        auth_server = new AuthSrv(cache, xfrout_client);
196
        auth_server->setVerbose(verbose_mode);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
197
        cout << "[b10-auth] Server created." << endl;
198

199
        if (address != NULL) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
200 201 202 203 204 205
            // XXX: we can only specify at most one explicit address.
            // This also means the server cannot run in the dual address
            // family mode if explicit addresses need to be specified.
            // We don't bother to fix this problem, however.  The -a option
            // is a short term workaround until we support dynamic listening
            // port allocation.
206 207 208 209 210 211
            io_service = new asio_link::IOService(auth_server, *port,
                                                  *address);
        } else {
            io_service = new asio_link::IOService(auth_server, *port,
                                                  use_ipv4, use_ipv6);
        }
JINMEI Tatuya's avatar
JINMEI Tatuya committed
212
        cout << "[b10-auth] IOService created." << endl;
213

JINMEI Tatuya's avatar
JINMEI Tatuya committed
214
        cc_session = new Session(io_service->get_io_service());
215
        cout << "[b10-auth] Configuration session channel created." << endl;
216

217 218 219
        config_session = new ModuleCCSession(specfile, *cc_session,
                                             my_config_handler,
                                             my_command_handler);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
220 221
        cout << "[b10-auth] Configuration channel established." << endl;

222 223 224 225
        if (uid != NULL) {
            changeUser(uid);
        }

226 227 228 229 230 231
        xfrin_session = new Session(io_service->get_io_service());
        cout << "[b10-auth] Xfrin session channel created." << endl;
        xfrin_session->establish(NULL);
        xfrin_session_established = true;
        cout << "[b10-auth] Xfrin session channel established." << endl;

232 233 234 235 236 237
        stats_session = new Session(io_service->get_io_service());
        cout << "[b10-auth] Stats session channel created." << endl;
        stats_session->establish(NULL);
        stats_session_established = true;
        cout << "[b10-auth] Stats session channel established." << endl;

238 239 240 241
        // XXX: with the current interface to asio_link we have to create
        // auth_server before io_service while Session needs io_service.
        // In a next step of refactoring we should make asio_link independent
        // from auth_server, and create io_service, auth_server, and
242 243
        // sessions in that order.
        auth_server->setXfrinSession(xfrin_session);
244
        auth_server->setStatsSession(stats_session);
245
        auth_server->setConfigSession(config_session);
246 247
        auth_server->updateConfig(ElementPtr());

248
        // create interval timer instance
249
        itimer = new asio_link::IntervalTimer(*io_service);
250 251
        // set up interval timer
        // register function to send statistics with interval
252 253
        itimer->setupTimer(boost::bind(statisticsTimerCallback,
                                       auth_server),
254 255 256
                           STATS_SEND_INTERVAL_SEC);
        cout << "[b10-auth] Interval timer set to send stats." << endl;

257
        cout << "[b10-auth] Server started." << endl;
258
        io_service->run();
259
    } catch (const std::exception& ex) {
JINMEI Tatuya's avatar
JINMEI Tatuya committed
260
        cerr << "[b10-auth] Initialization failed: " << ex.what() << endl;
261
        ret = 1;
262
    }
263

264 265 266 267
    if (stats_session_established) {
        stats_session->disconnect();
    }

268 269 270 271
    if (xfrin_session_established) {
        xfrin_session->disconnect();
    }

272 273
    delete itimer;
    delete stats_session;
274 275
    delete xfrin_session;
    delete config_session;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
276
    delete cc_session;
277
    delete io_service;
278
    delete auth_server;
279

280
    return (ret);
281
}