Blame view

babeld.c 33.3 KB
Juliusz Chroboczek committed
1
/*
Juliusz Chroboczek committed
2
Copyright (c) 2007, 2008 by Juliusz Chroboczek
dermiste committed
3
Copyright (c) 2010 by Vincent Gross
Juliusz Chroboczek committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <assert.h>

#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

Juliusz Chroboczek committed
42
#include "babeld.h"
Juliusz Chroboczek committed
43 44 45
#include "util.h"
#include "net.h"
#include "kernel.h"
Juliusz Chroboczek committed
46
#include "interface.h"
Juliusz Chroboczek committed
47
#include "source.h"
Juliusz Chroboczek committed
48 49 50 51
#include "neighbour.h"
#include "route.h"
#include "xroute.h"
#include "message.h"
Juliusz Chroboczek committed
52
#include "resend.h"
Juliusz Chroboczek committed
53
#include "configuration.h"
Juliusz Chroboczek committed
54
#include "local.h"
Matthieu Boutier committed
55
#include "rule.h"
Juliusz Chroboczek committed
56
#include "version.h"
Cédric Le Ninivin committed
57
#include "ctl.h"
Juliusz Chroboczek committed
58 59 60

struct timeval now;

Juliusz Chroboczek committed
61
unsigned char myid[8];
Juliusz Chroboczek committed
62
int have_id = 0;
Juliusz Chroboczek committed
63 64
int debug = 0;

Juliusz Chroboczek committed
65
int link_detect = 0;
Juliusz Chroboczek committed
66
int all_wireless = 0;
Matthieu Boutier committed
67
int has_ipv6_subtrees = 0;
Juliusz Chroboczek committed
68 69
int default_wireless_hello_interval = -1;
int default_wired_hello_interval = -1;
Juliusz Chroboczek committed
70
int resend_delay = -1;
Gabriel Kerneis committed
71
int random_id = 0;
Juliusz Chroboczek committed
72
int do_daemonise = 0;
73
int skip_kernel_setup = 0;
Matthieu Boutier committed
74
const char *logfile = NULL,
Juliusz Chroboczek committed
75 76
    *pidfile = "/var/run/babeld.pid",
    *state_file = "/var/lib/babel-state";
Juliusz Chroboczek committed
77

Juliusz Chroboczek committed
78 79 80
unsigned char *receive_buffer = NULL;
int receive_buffer_size = 0;

Juliusz Chroboczek committed
81
const unsigned char zeroes[16] = {0};
Juliusz Chroboczek committed
82 83 84
const unsigned char ones[16] =
    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
Juliusz Chroboczek committed
85 86 87 88

int protocol_port;
unsigned char protocol_group[16];
int protocol_socket = -1;
Juliusz Chroboczek committed
89
int kernel_socket = -1;
Juliusz Chroboczek committed
90
static int kernel_routes_changed = 0;
Matthieu Boutier committed
91
static int kernel_rules_changed = 0;
Julien Cristau committed
92 93
static int kernel_link_changed = 0;
static int kernel_addr_changed = 0;
Juliusz Chroboczek committed
94

Juliusz Chroboczek committed
95
struct timeval check_neighbours_timeout, check_interfaces_timeout;
Juliusz Chroboczek committed
96

Juliusz Chroboczek committed
97
static volatile sig_atomic_t exiting = 0, dumping = 0, reopening = 0;
Juliusz Chroboczek committed
98

Juliusz Chroboczek committed
99
static int accept_local_connections(void);
Juliusz Chroboczek committed
100
static void init_signals(void);
Juliusz Chroboczek committed
101
static void dump_tables(FILE *out);
Juliusz Chroboczek committed
102

Matthieu Boutier committed
103 104 105 106 107 108 109
static int
kernel_route_notify(struct kernel_route *route, void *closure)
{
    kernel_routes_changed = 1;
    return -1;
}

Matthieu Boutier committed
110 111 112 113 114 115 116
static int
kernel_addr_notify(struct kernel_addr *addr, void *closure)
{
    kernel_addr_changed = 1;
    return -1;
}

Matthieu Boutier committed
117 118 119 120 121 122 123 124 125 126 127 128 129
static int
kernel_link_notify(struct kernel_link *link, void *closure)
{
    struct interface *ifp;
    FOR_ALL_INTERFACES(ifp) {
        if(strcmp(ifp->name, link->ifname) == 0) {
            kernel_link_changed = 1;
            return -1;
        }
    }
    return 0;
}

Matthieu Boutier committed
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
static int
kernel_rule_notify(struct kernel_rule *rule, void *closure)
{
    int i;
    if(martian_prefix(rule->src, rule->src_plen))
        return 0;

    i = rule->priority - src_table_prio;

    if(i < 0 || SRC_TABLE_NUM <= i)
        return 0;

    kernel_rules_changed = 1;
    return -1;
}

Juliusz Chroboczek committed
146 147 148 149
int
main(int argc, char **argv)
{
    struct sockaddr_in6 sin6;
Gabriel Kerneis committed
150
    int rc, fd, i, opt;
Juliusz Chroboczek committed
151
    time_t expiry_time, source_expiry_time, kernel_dump_time;
Juliusz Chroboczek committed
152 153
    const char **config_files = NULL;
    int num_config_files = 0;
Juliusz Chroboczek committed
154 155
    void *vrc;
    unsigned int seed;
Matthieu Boutier committed
156
    struct interface *ifp;
Cédric Le Ninivin committed
157
    int ctl_sockfd;
Juliusz Chroboczek committed
158

Juliusz Chroboczek committed
159 160
    gettime(&now);

Juliusz Chroboczek committed
161 162 163 164 165 166
    rc = read_random_bytes(&seed, sizeof(seed));
    if(rc < 0) {
        perror("read(random)");
        seed = 42;
    }

Juliusz Chroboczek committed
167 168 169
    seed ^= (now.tv_sec ^ now.tv_usec);
    srandom(seed);

Juliusz Chroboczek committed
170
    parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
Juliusz Chroboczek committed
171
    protocol_port = 6696;
Juliusz Chroboczek committed
172
    change_smoothing_half_life(4);
Matthieu Boutier committed
173
    has_ipv6_subtrees = kernel_has_ipv6_subtrees();
Juliusz Chroboczek committed
174

Juliusz Chroboczek committed
175
    while(1) {
Juliusz Chroboczek committed
176
        opt = getopt(argc, argv,
Cédric Le Ninivin committed
177
                     "m:p:h:H:i:k:A:srS:d:g:G:lwz:M:t:T:c:C:DL:I:X:V");
Juliusz Chroboczek committed
178
        if(opt < 0)
Juliusz Chroboczek committed
179
            break;
Juliusz Chroboczek committed
180 181 182 183

        switch(opt) {
        case 'm':
            rc = parse_address(optarg, protocol_group, NULL);
Juliusz Chroboczek committed
184
            if(rc < 0)
Juliusz Chroboczek committed
185
                goto usage;
Juliusz Chroboczek committed
186 187
            if(protocol_group[0] != 0xff) {
                fprintf(stderr,
Juliusz Chroboczek committed
188 189
                        "%s is not a multicast address\n", optarg);
                goto usage;
Juliusz Chroboczek committed
190 191 192 193
            }
            if(protocol_group[1] != 2) {
                fprintf(stderr,
                        "Warning: %s is not a link-local multicast address\n",
Juliusz Chroboczek committed
194
                        optarg);
Juliusz Chroboczek committed
195
            }
Juliusz Chroboczek committed
196 197
            break;
        case 'p':
Juliusz Chroboczek committed
198 199 200
            protocol_port = parse_nat(optarg);
            if(protocol_port <= 0 || protocol_port > 0xFFFF)
                goto usage;
Juliusz Chroboczek committed
201 202
            break;
        case 'h':
Baptiste Jonglez committed
203
            default_wireless_hello_interval = parse_thousands(optarg);
Juliusz Chroboczek committed
204 205
            if(default_wireless_hello_interval <= 0 ||
               default_wireless_hello_interval > 0xFFFF * 10)
Juliusz Chroboczek committed
206 207 208
                goto usage;
            break;
        case 'H':
Baptiste Jonglez committed
209
            default_wired_hello_interval = parse_thousands(optarg);
Juliusz Chroboczek committed
210 211
            if(default_wired_hello_interval <= 0 ||
               default_wired_hello_interval > 0xFFFF * 10)
Juliusz Chroboczek committed
212 213 214
                goto usage;
            break;
        case 'k':
Juliusz Chroboczek committed
215
            kernel_metric = parse_nat(optarg);
Juliusz Chroboczek committed
216
            if(kernel_metric < 0 || kernel_metric > 0xFFFF)
Juliusz Chroboczek committed
217 218
                goto usage;
            break;
Juliusz Chroboczek committed
219
        case 'A':
Juliusz Chroboczek committed
220
            allow_duplicates = parse_nat(optarg);
Juliusz Chroboczek committed
221 222 223
            if(allow_duplicates < 0 || allow_duplicates > 0xFFFF)
                goto usage;
            break;
Juliusz Chroboczek committed
224
        case 's':
Juliusz Chroboczek committed
225
            split_horizon = 0;
Juliusz Chroboczek committed
226
            break;
Juliusz Chroboczek committed
227 228 229
        case 'r':
            random_id = 1;
            break;
Juliusz Chroboczek committed
230 231 232 233
        case 'S':
            state_file = optarg;
            break;
        case 'd':
Juliusz Chroboczek committed
234 235 236
            debug = parse_nat(optarg);
            if(debug < 0)
                goto usage;
Juliusz Chroboczek committed
237 238
            break;
        case 'g':
Juliusz Chroboczek committed
239
        case 'G':
Julien Cristau committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
            if(opt == 'g')
                local_server_write = 0;
            else
                local_server_write = 1;
            if(optarg[0] == '/') {
                local_server_port = -1;
                free(local_server_path);
                local_server_path = strdup(optarg);
            } else {
                local_server_port = parse_nat(optarg);
                free(local_server_path);
                local_server_path = NULL;
                if(local_server_port <= 0 || local_server_port > 0xFFFF)
                    goto usage;
            }
Juliusz Chroboczek committed
255 256
            break;
        case 'l':
Juliusz Chroboczek committed
257
            link_detect = 1;
Juliusz Chroboczek committed
258 259
            break;
        case 'w':
Juliusz Chroboczek committed
260
            all_wireless = 1;
Juliusz Chroboczek committed
261
            break;
Juliusz Chroboczek committed
262 263
        case 'z':
            {
Juliusz Chroboczek committed
264 265 266
                char *comma;
                diversity_kind = (int)strtol(optarg, &comma, 0);
                if(*comma == '\0')
Juliusz Chroboczek committed
267
                    diversity_factor = 128;
Juliusz Chroboczek committed
268 269
                else if(*comma == ',')
                    diversity_factor = parse_nat(comma + 1);
Juliusz Chroboczek committed
270
                else
Juliusz Chroboczek committed
271
                    goto usage;
Juliusz Chroboczek committed
272 273 274 275
                if(diversity_factor <= 0 || diversity_factor > 256)
                    goto usage;
            }
            break;
Juliusz Chroboczek committed
276 277 278 279 280 281 282
        case 'M': {
            int l = parse_nat(optarg);
            if(l < 0 || l > 3600)
                goto usage;
            change_smoothing_half_life(l);
            break;
        }
Juliusz Chroboczek committed
283
        case 't':
Juliusz Chroboczek committed
284
            export_table = parse_nat(optarg);
Juliusz Chroboczek committed
285
            if(export_table < 0 || export_table > 0xFFFF)
Juliusz Chroboczek committed
286 287 288
                goto usage;
            break;
        case 'T':
289
            if(add_import_table(parse_nat(optarg)))
Juliusz Chroboczek committed
290 291 292
                goto usage;
            break;
        case 'c':
Juliusz Chroboczek committed
293 294 295 296 297 298 299
            config_files = realloc(config_files,
                                   (num_config_files + 1) * sizeof(char*));
            if(config_files == NULL) {
                fprintf(stderr, "Couldn't allocate config file.\n");
                exit(1);
            }
            config_files[num_config_files++] = optarg;
Juliusz Chroboczek committed
300 301
            break;
        case 'C':
Juliusz Chroboczek committed
302
            rc = parse_config_from_string(optarg, strlen(optarg), NULL);
Juliusz Chroboczek committed
303
            if(rc != CONFIG_ACTION_DONE) {
Juliusz Chroboczek committed
304 305 306 307
                fprintf(stderr,
                        "Couldn't parse configuration from command line.\n");
                exit(1);
            }
Juliusz Chroboczek committed
308 309
            break;
        case 'D':
Juliusz Chroboczek committed
310
            do_daemonise = 1;
Juliusz Chroboczek committed
311 312 313 314 315 316 317
            break;
        case 'L':
            logfile = optarg;
            break;
        case 'I':
            pidfile = optarg;
            break;
Juliusz Chroboczek committed
318 319 320 321
        case 'V':
            fprintf(stderr, "%s\n", BABELD_VERSION);
            exit(0);
            break;
Cédric Le Ninivin committed
322 323 324
        case 'X':
            control_socket_path = optarg;
            break;
Juliusz Chroboczek committed
325 326
        default:
            goto usage;
Juliusz Chroboczek committed
327 328 329
        }
    }

Juliusz Chroboczek committed
330 331 332 333 334 335 336 337 338
    if(num_config_files == 0) {
        if(access("/etc/babeld.conf", F_OK) >= 0) {
            config_files = malloc(sizeof(char*));
            if(config_files == NULL) {
                fprintf(stderr, "Couldn't allocate config file.\n");
                exit(1);
            }
            config_files[num_config_files++] = "/etc/babeld.conf";
        }
Juliusz Chroboczek committed
339
    }
Juliusz Chroboczek committed
340 341

    for(i = 0; i < num_config_files; i++) {
Juliusz Chroboczek committed
342
        int line;
Juliusz Chroboczek committed
343
        rc = parse_config_from_file(config_files[i], &line);
Juliusz Chroboczek committed
344 345
        if(rc < 0) {
            fprintf(stderr,
Juliusz Chroboczek committed
346 347
                    "Couldn't parse configuration from file %s "
                    "(error at line %d).\n",
Juliusz Chroboczek committed
348
                    config_files[i], line);
Juliusz Chroboczek committed
349 350 351 352
            exit(1);
        }
    }

Juliusz Chroboczek committed
353 354
    free(config_files);

Juliusz Chroboczek committed
355 356 357
    if(default_wireless_hello_interval <= 0)
        default_wireless_hello_interval = 4000;
    default_wireless_hello_interval = MAX(default_wireless_hello_interval, 5);
Juliusz Chroboczek committed
358

Juliusz Chroboczek committed
359 360 361
    if(default_wired_hello_interval <= 0)
        default_wired_hello_interval = 4000;
    default_wired_hello_interval = MAX(default_wired_hello_interval, 5);
Juliusz Chroboczek committed
362

Juliusz Chroboczek committed
363
    resend_delay = 2000;
Juliusz Chroboczek committed
364 365
    resend_delay = MIN(resend_delay, default_wireless_hello_interval / 2);
    resend_delay = MIN(resend_delay, default_wired_hello_interval / 2);
Juliusz Chroboczek committed
366 367
    resend_delay = MAX(resend_delay, 20);

Juliusz Chroboczek committed
368 369
    if(do_daemonise) {
        if(logfile == NULL)
Juliusz Chroboczek committed
370
            logfile = "/var/log/babeld.log";
Juliusz Chroboczek committed
371 372
    }

Juliusz Chroboczek committed
373 374 375
    rc = reopen_logfile();
    if(rc < 0) {
        perror("reopen_logfile()");
Juliusz Chroboczek committed
376
        exit(1);
Juliusz Chroboczek committed
377 378 379 380 381
    }

    fd = open("/dev/null", O_RDONLY);
    if(fd < 0) {
        perror("open(null)");
Juliusz Chroboczek committed
382
        exit(1);
Juliusz Chroboczek committed
383 384 385 386 387
    }

    rc = dup2(fd, 0);
    if(rc < 0) {
        perror("dup2(null, 0)");
Juliusz Chroboczek committed
388
        exit(1);
Juliusz Chroboczek committed
389 390 391 392 393 394 395 396
    }

    close(fd);

    if(do_daemonise) {
        rc = daemonise();
        if(rc < 0) {
            perror("daemonise");
Juliusz Chroboczek committed
397
            exit(1);
Juliusz Chroboczek committed
398 399 400
        }
    }

Juliusz Chroboczek committed
401
    if(pidfile && pidfile[0] != '\0') {
Juliusz Chroboczek committed
402 403 404 405 406 407
        int pfd, len;
        char buf[100];

        len = snprintf(buf, 100, "%lu", (unsigned long)getpid());
        if(len < 0 || len >= 100) {
            perror("snprintf(getpid)");
Juliusz Chroboczek committed
408
            exit(1);
Juliusz Chroboczek committed
409 410 411 412
        }

        pfd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644);
        if(pfd < 0) {
Juliusz Chroboczek committed
413 414 415 416
            char buf[40];
            snprintf(buf, 40, "creat(%s)", pidfile);
            buf[39] = '\0';
            perror(buf);
Juliusz Chroboczek committed
417
            exit(1);
Juliusz Chroboczek committed
418 419 420 421 422
        }

        rc = write(pfd, buf, len);
        if(rc < len) {
            perror("write(pidfile)");
Juliusz Chroboczek committed
423
            goto fail_pid;
Juliusz Chroboczek committed
424 425 426 427 428
        }

        close(pfd);
    }

Juliusz Chroboczek committed
429 430 431
    rc = kernel_setup(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup failed.\n");
Juliusz Chroboczek committed
432
        goto fail_pid;
Juliusz Chroboczek committed
433 434 435 436 437 438
    }

    rc = kernel_setup_socket(1);
    if(rc < 0) {
        fprintf(stderr, "kernel_setup_socket failed.\n");
        kernel_setup(0);
Juliusz Chroboczek committed
439
        goto fail_pid;
Juliusz Chroboczek committed
440
    }
Juliusz Chroboczek committed
441

Juliusz Chroboczek committed
442 443 444
    rc = finalise_config();
    if(rc < 0) {
        fprintf(stderr, "Couldn't finalise configuration.\n");
Juliusz Chroboczek committed
445
        goto fail;
Juliusz Chroboczek committed
446 447
    }

Juliusz Chroboczek committed
448
    for(i = optind; i < argc; i++) {
Juliusz Chroboczek committed
449
        vrc = add_interface(argv[i], NULL);
Juliusz Chroboczek committed
450
        if(vrc == NULL)
Juliusz Chroboczek committed
451
            goto fail;
Juliusz Chroboczek committed
452 453
    }

Matthieu Boutier committed
454
    if(interfaces == NULL) {
Juliusz Chroboczek committed
455 456 457 458
        fprintf(stderr, "Eek... asked to run on no interfaces!\n");
        goto fail;
    }

Juliusz Chroboczek committed
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476
    if(!have_id && !random_id) {
        /* We use all available interfaces here, since this increases the
           chances of getting a stable router-id in case the set of Babel
           interfaces changes. */

        for(i = 1; i < 256; i++) {
            char buf[IF_NAMESIZE], *ifname;
            unsigned char eui[8];
            ifname = if_indextoname(i, buf);
            if(ifname == NULL)
                continue;
            rc = if_eui64(ifname, i, eui);
            if(rc < 0)
                continue;
            memcpy(myid, eui, 8);
            have_id = 1;
            break;
        }
Juliusz Chroboczek committed
477 478
    }

Juliusz Chroboczek committed
479 480 481 482 483 484 485 486 487 488 489 490
    if(!have_id) {
        if(!random_id)
            fprintf(stderr,
                    "Warning: couldn't find router id -- "
                    "using random value.\n");
        rc = read_random_bytes(myid, 8);
        if(rc < 0) {
            perror("read(random)");
            goto fail;
        }
        /* Clear group and global bits */
        myid[0] &= ~3;
Juliusz Chroboczek committed
491
    }
Juliusz Chroboczek committed
492

Juliusz Chroboczek committed
493
    myseqno = (random() & 0xFFFF);
Juliusz Chroboczek committed
494 495 496

    fd = open(state_file, O_RDONLY);
    if(fd < 0 && errno != ENOENT)
Juliusz Chroboczek committed
497
        perror("open(babel-state)");
Juliusz Chroboczek committed
498
    rc = unlink(state_file);
Juliusz Chroboczek committed
499
    if(fd >= 0 && rc < 0) {
Juliusz Chroboczek committed
500
        perror("unlink(babel-state)");
Juliusz Chroboczek committed
501
        /* If we couldn't unlink it, it's probably stale. */
Juliusz Chroboczek committed
502 503 504 505 506
        close(fd);
        fd = -1;
    }
    if(fd >= 0) {
        char buf[100];
Juliusz Chroboczek committed
507
        int s;
Juliusz Chroboczek committed
508 509
        rc = read(fd, buf, 99);
        if(rc < 0) {
Juliusz Chroboczek committed
510
            perror("read(babel-state)");
Juliusz Chroboczek committed
511 512
        } else {
            buf[rc] = '\0';
Juliusz Chroboczek committed
513 514 515
            rc = sscanf(buf, "%d\n", &s);
            if(rc == 1 && s >= 0 && s <= 0xFFFF) {
                myseqno = seqno_plus(s, 1);
Juliusz Chroboczek committed
516
            } else {
Juliusz Chroboczek committed
517
                fprintf(stderr, "Couldn't parse babel-state.\n");
Juliusz Chroboczek committed
518 519 520
            }
        }
        close(fd);
Juliusz Chroboczek committed
521
        fd = -1;
Juliusz Chroboczek committed
522 523
    }

Juliusz Chroboczek committed
524
    protocol_socket = babel_socket(protocol_port);
Juliusz Chroboczek committed
525 526 527 528 529
    if(protocol_socket < 0) {
        perror("Couldn't create link local socket");
        goto fail;
    }

Juliusz Chroboczek committed
530 531 532 533 534 535
    if(local_server_port >= 0) {
        local_server_socket = tcp_server_socket(local_server_port, 1);
        if(local_server_socket < 0) {
            perror("local_server_socket");
            goto fail;
        }
Julien Cristau committed
536 537 538 539 540 541
    } else if(local_server_path) {
        local_server_socket = unix_server_socket(local_server_path);
        if(local_server_socket < 0) {
            perror("local_server_socket");
            goto fail;
        }
Juliusz Chroboczek committed
542 543
    }

Cédric Le Ninivin committed
544 545 546 547 548 549
    ctl_sockfd = init_control_socket();
    if(ctl_sockfd < 0) {
        perror("Couldn't create control socket");
        goto fail;
    }

Juliusz Chroboczek committed
550
    init_signals();
Juliusz Chroboczek committed
551 552 553
    rc = resize_receive_buffer(1500);
    if(rc < 0)
        goto fail;
Juliusz Chroboczek committed
554 555 556
    if(receive_buffer == NULL)
        goto fail;

Juliusz Chroboczek committed
557 558
    check_interfaces();

Juliusz Chroboczek committed
559 560 561
    rc = check_xroutes(0);
    if(rc < 0)
        fprintf(stderr, "Warning: couldn't check exported routes.\n");
Matthieu Boutier committed
562 563 564
    rc = check_rules();
    if(rc < 0)
        fprintf(stderr, "Warning: couldn't check rules.\n");
Juliusz Chroboczek committed
565

Juliusz Chroboczek committed
566
    kernel_routes_changed = 0;
Matthieu Boutier committed
567
    kernel_rules_changed = 0;
Julien Cristau committed
568 569
    kernel_link_changed = 0;
    kernel_addr_changed = 0;
Juliusz Chroboczek committed
570
    kernel_dump_time = now.tv_sec + roughly(30);
Juliusz Chroboczek committed
571
    schedule_neighbours_check(5000, 1);
Juliusz Chroboczek committed
572
    schedule_interfaces_check(30000, 1);
Juliusz Chroboczek committed
573 574
    expiry_time = now.tv_sec + roughly(30);
    source_expiry_time = now.tv_sec + roughly(300);
Juliusz Chroboczek committed
575

Juliusz Chroboczek committed
576 577
    /* Make some noise so that others notice us, and send retractions in
       case we were restarted recently */
Matthieu Boutier committed
578 579
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
Juliusz Chroboczek committed
580
            continue;
Juliusz Chroboczek committed
581
        /* Apply jitter before we send the first message. */
Juliusz Chroboczek committed
582
        usleep(roughly(10000));
Juliusz Chroboczek committed
583
        gettime(&now);
Matthieu Boutier committed
584 585
        send_hello(ifp);
        send_wildcard_retraction(ifp);
Juliusz Chroboczek committed
586
        flushupdates(ifp);
Juliusz Chroboczek committed
587
        flushbuf(&ifp->buf, ifp);
Juliusz Chroboczek committed
588 589
    }

Matthieu Boutier committed
590 591
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
Juliusz Chroboczek committed
592 593 594
            continue;
        usleep(roughly(10000));
        gettime(&now);
Matthieu Boutier committed
595 596 597
        send_hello(ifp);
        send_wildcard_retraction(ifp);
        send_self_update(ifp);
Juliusz Chroboczek committed
598
        send_multicast_request(ifp, NULL, 0, NULL, 0);
Matthieu Boutier committed
599
        flushupdates(ifp);
Juliusz Chroboczek committed
600
        flushbuf(&ifp->buf, ifp);
Juliusz Chroboczek committed
601 602 603 604 605 606
    }

    debugf("Entering main loop.\n");

    while(1) {
        struct timeval tv;
Juliusz Chroboczek committed
607
        struct neighbour *neigh;
Cédric Le Ninivin committed
608 609
        fd_set readfds, writefds;
        struct ctl *ctl, *ctl_next;
Juliusz Chroboczek committed
610

Juliusz Chroboczek committed
611
        gettime(&now);
Juliusz Chroboczek committed
612

Juliusz Chroboczek committed
613
        tv = check_neighbours_timeout;
Juliusz Chroboczek committed
614
        timeval_min(&tv, &check_interfaces_timeout);
Juliusz Chroboczek committed
615
        timeval_min_sec(&tv, expiry_time);
Juliusz Chroboczek committed
616
        timeval_min_sec(&tv, source_expiry_time);
Juliusz Chroboczek committed
617
        timeval_min_sec(&tv, kernel_dump_time);
Juliusz Chroboczek committed
618
        timeval_min(&tv, &resend_time);
Matthieu Boutier committed
619 620
        FOR_ALL_INTERFACES(ifp) {
            if(!if_up(ifp))
Juliusz Chroboczek committed
621
                continue;
Juliusz Chroboczek committed
622
            timeval_min(&tv, &ifp->buf.timeout);
Matthieu Boutier committed
623 624 625
            timeval_min(&tv, &ifp->hello_timeout);
            timeval_min(&tv, &ifp->update_timeout);
            timeval_min(&tv, &ifp->update_flush_timeout);
Juliusz Chroboczek committed
626
        }
Juliusz Chroboczek committed
627 628 629
        FOR_ALL_NEIGHBOURS(neigh) {
            timeval_min(&tv, &neigh->buf.timeout);
        }
Juliusz Chroboczek committed
630
        FD_ZERO(&readfds);
Cédric Le Ninivin committed
631
        FD_ZERO(&writefds);
Juliusz Chroboczek committed
632
        if(timeval_compare(&tv, &now) > 0) {
Juliusz Chroboczek committed
633
            int maxfd = 0;
Juliusz Chroboczek committed
634 635
            timeval_minus(&tv, &tv, &now);
            FD_SET(protocol_socket, &readfds);
Juliusz Chroboczek committed
636
            maxfd = MAX(maxfd, protocol_socket);
Grégoire Henry committed
637
            if(kernel_socket < 0) kernel_setup_socket(1);
Juliusz Chroboczek committed
638
            if(kernel_socket >= 0) {
Juliusz Chroboczek committed
639
                FD_SET(kernel_socket, &readfds);
Juliusz Chroboczek committed
640 641
                maxfd = MAX(maxfd, kernel_socket);
            }
Juliusz Chroboczek committed
642 643
            if(local_server_socket >= 0 &&
               num_local_sockets < MAX_LOCAL_SOCKETS) {
Juliusz Chroboczek committed
644 645 646
                FD_SET(local_server_socket, &readfds);
                maxfd = MAX(maxfd, local_server_socket);
            }
Juliusz Chroboczek committed
647
            for(i = 0; i < num_local_sockets; i++) {
Juliusz Chroboczek committed
648 649
                FD_SET(local_sockets[i].fd, &readfds);
                maxfd = MAX(maxfd, local_sockets[i].fd);
Juliusz Chroboczek committed
650
            }
Cédric Le Ninivin committed
651 652 653 654 655 656 657 658 659 660
            FD_SET(ctl_sockfd, &readfds);
            maxfd = MAX(maxfd, ctl_sockfd);
            for(ctl = ctl_connection; ctl; ctl = ctl->next) {
                if(ctl->write < ctl->buffer_out.end)
                    FD_SET(ctl->fd, &writefds);
                else
                    FD_SET(ctl->fd, &readfds);
                maxfd = MAX(maxfd, ctl->fd);
            }
            rc = select(maxfd + 1, &readfds, &writefds, NULL, &tv);
Juliusz Chroboczek committed
661
            if(rc < 0) {
Juliusz Chroboczek committed
662
                if(errno != EINTR) {
Juliusz Chroboczek committed
663
                    perror("select");
Juliusz Chroboczek committed
664
                    sleep(1);
Juliusz Chroboczek committed
665
                }
Juliusz Chroboczek committed
666 667
                rc = 0;
                FD_ZERO(&readfds);
Juliusz Chroboczek committed
668 669 670
            }
        }

Juliusz Chroboczek committed
671
        gettime(&now);
Juliusz Chroboczek committed
672 673 674 675

        if(exiting)
            break;

Matthieu Boutier committed
676 677 678
        if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds)) {
            struct kernel_filter filter = {0};
            filter.route = kernel_route_notify;
Matthieu Boutier committed
679
            filter.addr = kernel_addr_notify;
Matthieu Boutier committed
680
            filter.link = kernel_link_notify;
Matthieu Boutier committed
681
            filter.rule = kernel_rule_notify;
Matthieu Boutier committed
682 683
            kernel_callback(&filter);
        }
Juliusz Chroboczek committed
684

Juliusz Chroboczek committed
685
        if(FD_ISSET(protocol_socket, &readfds)) {
Juliusz Chroboczek committed
686
	    unsigned char to[16];
Juliusz Chroboczek committed
687 688
            rc = babel_recv(protocol_socket,
                            receive_buffer, receive_buffer_size,
Juliusz Chroboczek committed
689
                            (struct sockaddr*)&sin6, sizeof(sin6), to);
Juliusz Chroboczek committed
690 691 692
            if(rc < 0) {
                if(errno != EAGAIN && errno != EINTR) {
                    perror("recv");
Juliusz Chroboczek committed
693
                    sleep(1);
Juliusz Chroboczek committed
694 695
                }
            } else {
Matthieu Boutier committed
696 697
                FOR_ALL_INTERFACES(ifp) {
                    if(!if_up(ifp))
Juliusz Chroboczek committed
698
                        continue;
Matthieu Boutier committed
699 700
                    if(ifp->ifindex == sin6.sin6_scope_id) {
                        parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
Juliusz Chroboczek committed
701
                                     receive_buffer, rc, to);
Juliusz Chroboczek committed
702 703
                        VALGRIND_MAKE_MEM_UNDEFINED(receive_buffer,
                                                    receive_buffer_size);
Juliusz Chroboczek committed
704 705 706 707 708 709
                        break;
                    }
                }
            }
        }

Juliusz Chroboczek committed
710 711
        if(local_server_socket >= 0 && FD_ISSET(local_server_socket, &readfds))
           accept_local_connections();
Juliusz Chroboczek committed
712

Juliusz Chroboczek committed
713 714
        i = 0;
        while(i < num_local_sockets) {
Juliusz Chroboczek committed
715 716
            if(FD_ISSET(local_sockets[i].fd, &readfds)) {
                rc = local_read(&local_sockets[i]);
Juliusz Chroboczek committed
717
                if(rc <= 0) {
Juliusz Chroboczek committed
718
                    if(rc < 0) {
Juliusz Chroboczek committed
719
                        if(errno == EINTR || errno == EAGAIN)
Juliusz Chroboczek committed
720
                            continue;
Juliusz Chroboczek committed
721
                        perror("read(local_socket)");
Juliusz Chroboczek committed
722
                    }
Juliusz Chroboczek committed
723
                    local_socket_destroy(i);
Juliusz Chroboczek committed
724
                }
Juliusz Chroboczek committed
725
            }
Juliusz Chroboczek committed
726
            i++;
Juliusz Chroboczek committed
727 728
        }

Cédric Le Ninivin committed
729 730 731 732 733 734 735 736 737 738
        if(FD_ISSET(ctl_sockfd, &readfds)) {
            accept_ctl_connection(ctl_sockfd);
        }
        for(ctl = ctl_connection; ctl; ctl = ctl_next) {
            ctl_next = ctl->next;
            if (FD_ISSET(ctl->fd, &writefds))
                ctl_write(ctl);
            if (FD_ISSET(ctl->fd, &readfds))
                ctl_read(ctl);
        }
Juliusz Chroboczek committed
739
        if(reopening) {
Juliusz Chroboczek committed
740
            kernel_dump_time = now.tv_sec;
Juliusz Chroboczek committed
741
            check_neighbours_timeout = now;
Juliusz Chroboczek committed
742
            expiry_time = now.tv_sec;
Juliusz Chroboczek committed
743 744 745 746 747
            rc = reopen_logfile();
            if(rc < 0) {
                perror("reopen_logfile");
                break;
            }
Juliusz Chroboczek committed
748
            reopening = 0;
Juliusz Chroboczek committed
749 750
        }

Juliusz Chroboczek committed
751
        if(kernel_link_changed || kernel_addr_changed) {
Matthieu Boutier committed
752
            check_interfaces();
Julien Cristau committed
753 754 755
            kernel_link_changed = 0;
        }

Juliusz Chroboczek committed
756
        if(kernel_routes_changed || kernel_addr_changed ||
Matthieu Boutier committed
757
           kernel_rules_changed || now.tv_sec >= kernel_dump_time) {
Juliusz Chroboczek committed
758 759
            rc = check_xroutes(1);
            if(rc < 0)
Juliusz Chroboczek committed
760
                fprintf(stderr, "Warning: couldn't check exported routes.\n");
Matthieu Boutier committed
761 762 763
            rc = check_rules();
            if(rc < 0)
                fprintf(stderr, "Warning: couldn't check rules.\n");
Matthieu Boutier committed
764 765
            kernel_routes_changed = kernel_rules_changed =
                kernel_addr_changed = 0;
Juliusz Chroboczek committed
766
            if(kernel_socket >= 0)
Juliusz Chroboczek committed
767
                kernel_dump_time = now.tv_sec + roughly(300);
Juliusz Chroboczek committed
768
            else
Juliusz Chroboczek committed
769
                kernel_dump_time = now.tv_sec + roughly(30);
Juliusz Chroboczek committed
770 771
        }

Juliusz Chroboczek committed
772
        if(timeval_compare(&check_neighbours_timeout, &now) < 0) {
Juliusz Chroboczek committed
773 774
            int msecs;
            msecs = check_neighbours();
Juliusz Chroboczek committed
775 776
            /* Multiply by 3/2 to allow neighbours to expire. */
            msecs = MAX(3 * msecs / 2, 10);
Juliusz Chroboczek committed
777
            schedule_neighbours_check(msecs, 1);
Juliusz Chroboczek committed
778 779
        }

Juliusz Chroboczek committed
780
        if(timeval_compare(&check_interfaces_timeout, &now) < 0) {
Matthieu Boutier committed
781
            check_interfaces();
Juliusz Chroboczek committed
782 783 784 785
            schedule_interfaces_check(30000, 1);
        }

        if(now.tv_sec >= expiry_time) {
Juliusz Chroboczek committed
786
            expire_routes();
Juliusz Chroboczek committed
787
            expire_resend();
Juliusz Chroboczek committed
788
            expiry_time = now.tv_sec + roughly(30);
Juliusz Chroboczek committed
789 790
        }

Juliusz Chroboczek committed
791 792
        if(now.tv_sec >= source_expiry_time) {
            expire_sources();
Juliusz Chroboczek committed
793
            source_expiry_time = now.tv_sec + roughly(300);
Juliusz Chroboczek committed
794 795
        }

Matthieu Boutier committed
796 797
        FOR_ALL_INTERFACES(ifp) {
            if(!if_up(ifp))
Juliusz Chroboczek committed
798
                continue;
Matthieu Boutier committed
799 800 801
            if(timeval_compare(&now, &ifp->hello_timeout) >= 0)
                send_hello(ifp);
            if(timeval_compare(&now, &ifp->update_timeout) >= 0)
Matthieu Boutier committed
802
                send_update(ifp, 0, NULL, 0, NULL, 0);
Matthieu Boutier committed
803 804
            if(timeval_compare(&now, &ifp->update_flush_timeout) >= 0)
                flushupdates(ifp);
Juliusz Chroboczek committed
805 806
        }

Juliusz Chroboczek committed
807 808 809 810
        if(resend_time.tv_sec != 0) {
            if(timeval_compare(&now, &resend_time) >= 0)
                do_resend();
        }
Juliusz Chroboczek committed
811

Matthieu Boutier committed
812 813
        FOR_ALL_INTERFACES(ifp) {
            if(!if_up(ifp))
Juliusz Chroboczek committed
814
                continue;
Juliusz Chroboczek committed
815
            if(ifp->buf.timeout.tv_sec != 0) {
Juliusz Chroboczek committed
816 817
                if(timeval_compare(&now, &ifp->buf.timeout) >= 0) {
                    flushupdates(ifp);
Juliusz Chroboczek committed
818
                    flushbuf(&ifp->buf, ifp);
Juliusz Chroboczek committed
819
                }
Juliusz Chroboczek committed
820 821 822
            }
        }

Juliusz Chroboczek committed
823 824 825
        FOR_ALL_NEIGHBOURS(neigh) {
            if(neigh->buf.timeout.tv_sec != 0) {
                if(timeval_compare(&now, &neigh->buf.timeout) >= 0) {
Juliusz Chroboczek committed
826
                    flushbuf(&neigh->buf, neigh->ifp);
Juliusz Chroboczek committed
827 828 829 830
                }
            }
        }

Juliusz Chroboczek committed
831
        if(UNLIKELY(debug || dumping)) {
Juliusz Chroboczek committed
832
            dump_tables(stdout);
Juliusz Chroboczek committed
833 834
            dumping = 0;
        }
Juliusz Chroboczek committed
835 836 837
    }

    debugf("Exiting...\n");
Juliusz Chroboczek committed
838
    usleep(roughly(10000));
Juliusz Chroboczek committed
839
    gettime(&now);
Juliusz Chroboczek committed
840

Juliusz Chroboczek committed
841 842
    /* We need to flush so interface_up won't try to reinstall. */
    flush_all_routes();
Juliusz Chroboczek committed
843

Matthieu Boutier committed
844 845
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
Juliusz Chroboczek committed
846
            continue;
Matthieu Boutier committed
847
        send_wildcard_retraction(ifp);
Juliusz Chroboczek committed
848
        /* Make sure that we expire quickly from our neighbours'
Juliusz Chroboczek committed
849
           association caches. */
Juliusz Chroboczek committed
850
        send_hello_noihu(ifp, 10);
Juliusz Chroboczek committed
851
        flushbuf(&ifp->buf, ifp);
Juliusz Chroboczek committed
852
        usleep(roughly(1000));
Juliusz Chroboczek committed
853
        gettime(&now);
Juliusz Chroboczek committed
854
    }
Matthieu Boutier committed
855 856
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
Juliusz Chroboczek committed
857
            continue;
Juliusz Chroboczek committed
858
        /* Make sure they got it. */
Matthieu Boutier committed
859
        send_wildcard_retraction(ifp);
Juliusz Chroboczek committed
860
        send_hello_noihu(ifp, 1);
Juliusz Chroboczek committed
861
        flushbuf(&ifp->buf, ifp);
Juliusz Chroboczek committed
862
        usleep(roughly(10000));
Juliusz Chroboczek committed
863
        gettime(&now);
Matthieu Boutier committed
864
        interface_up(ifp, 0);
Juliusz Chroboczek committed
865
    }
Matthieu Boutier committed
866
    release_tables();
Grégoire Henry committed
867
    kernel_setup_socket(0);
Juliusz Chroboczek committed
868
    kernel_setup(0);
Juliusz Chroboczek committed
869 870 871

    fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
    if(fd < 0) {
Juliusz Chroboczek committed
872
        perror("creat(babel-state)");
Juliusz Chroboczek committed
873
        unlink(state_file);
Juliusz Chroboczek committed
874
    } else {
Juliusz Chroboczek committed
875 876 877
        char buf[10];
        rc = snprintf(buf, 10, "%d\n", (int)myseqno);
        if(rc < 0 || rc >= 10) {
Juliusz Chroboczek committed
878
            fprintf(stderr, "write(babel-state): overflow.\n");
Juliusz Chroboczek committed
879
            unlink(state_file);
Juliusz Chroboczek committed
880 881 882 883 884 885 886
        } else {
            rc = write(fd, buf, rc);
            if(rc < 0) {
                perror("write(babel-state)");
                unlink(state_file);
            }
            fsync(fd);
Juliusz Chroboczek committed
887
        }
Juliusz Chroboczek committed
888 889
        close(fd);
    }
Julien Cristau committed
890 891 892 893
    if(local_server_socket >= 0 && local_server_path) {
        unlink(local_server_path);
        free(local_server_path);
    }
Juliusz Chroboczek committed
894 895
    if(pidfile)
        unlink(pidfile);
Juliusz Chroboczek committed
896
    debugf("Done.\n");
Juliusz Chroboczek committed
897 898
    return 0;

Juliusz Chroboczek committed
899
 usage:
Juliusz Chroboczek committed
900
    fprintf(stderr,
Juliusz Chroboczek committed
901 902 903 904
            "%s\n"
            "Syntax: babeld "
            "[-V] [-m multicast_address] [-p port] [-S state-file]\n"
            "               "
Juliusz Chroboczek committed
905
            "[-h hello] [-H wired_hello] [-z kind[,factor]]\n"
Juliusz Chroboczek committed
906
            "               "
Juliusz Chroboczek committed
907
            "[-g port] [-G port] [-k metric] [-A metric] [-s] [-l] [-w] [-r]\n"
Juliusz Chroboczek committed
908
            "               "
Juliusz Chroboczek committed
909
            "[-u] [-t table] [-T table] [-c file] [-C statement]\n"
Juliusz Chroboczek committed
910
            "               "
Cédric Le Ninivin committed
911
            "[-d level] [-D] [-L logfile] [-I pidfile] [-X control-socket]\n"
Juliusz Chroboczek committed
912
            "               "
Juliusz Chroboczek committed
913
            "interface...\n",
Juliusz Chroboczek committed
914
            BABELD_VERSION);
Juliusz Chroboczek committed
915 916 917
    exit(1);

 fail:
Matthieu Boutier committed
918 919
    FOR_ALL_INTERFACES(ifp) {
        if(!if_up(ifp))
Juliusz Chroboczek committed
920
            continue;
Matthieu Boutier committed
921
        interface_up(ifp, 0);
Juliusz Chroboczek committed
922
    }
Grégoire Henry committed
923
    kernel_setup_socket(0);
Juliusz Chroboczek committed
924
    kernel_setup(0);
Juliusz Chroboczek committed
925 926 927
 fail_pid:
    if(pidfile)
        unlink(pidfile);
Juliusz Chroboczek committed
928 929 930
    exit(1);
}

Baptiste Jonglez committed
931
static int
Juliusz Chroboczek committed
932
accept_local_connections()
Baptiste Jonglez committed
933
{
Juliusz Chroboczek committed
934
    int rc, s;
Juliusz Chroboczek committed
935
    struct local_socket *ls;
Baptiste Jonglez committed
936

Juliusz Chroboczek committed
937
    if(local_server_socket < 0)
Baptiste Jonglez committed
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
        return 0;

    s = accept(local_server_socket, NULL, NULL);

    if(s < 0) {
        if(errno != EINTR && errno != EAGAIN) {
            perror("accept(local_server_socket)");
            return -1;
        }
        return 0;
    }

    if(num_local_sockets >= MAX_LOCAL_SOCKETS) {
        /* This should never happen, since we don't select for
           the server socket in this case.  But I'm paranoid. */
        fprintf(stderr, "Internal error: too many local sockets.\n");
        close(s);
        return -1;
    }

Baptiste Jonglez committed
958 959 960 961 962 963 964 965 966 967 968 969 970 971
    rc = fcntl(s, F_GETFL, 0);
    if(rc < 0) {
        fprintf(stderr, "Unable to get flags of local socket.\n");
        close(s);
        return -1;
    }

    rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
    if(rc < 0) {
        fprintf(stderr, "Unable to set flags of local socket.\n");
        close(s);
        return -1;
    }

Juliusz Chroboczek committed
972
    ls = local_socket_create(s);
Juliusz Chroboczek committed
973 974 975 976 977 978
    if(ls == NULL) {
        fprintf(stderr, "Unable create local socket.\n");
        close(s);
        return -1;
    }
    local_header(ls);
Baptiste Jonglez committed
979 980 981
    return 1;
}

Juliusz Chroboczek committed
982 983 984 985 986
void
schedule_neighbours_check(int msecs, int override)
{
    struct timeval timeout;

Juliusz Chroboczek committed
987
    timeval_add_msec(&timeout, &now, roughly(msecs));
Juliusz Chroboczek committed
988 989 990 991 992 993
    if(override)
        check_neighbours_timeout = timeout;
    else
        timeval_min(&check_neighbours_timeout, &timeout);
}

Juliusz Chroboczek committed
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
void
schedule_interfaces_check(int msecs, int override)
{
    struct timeval timeout;

    timeval_add_msec(&timeout, &now, roughly(msecs));
    if(override)
        check_interfaces_timeout = timeout;
    else
        timeval_min(&check_interfaces_timeout, &timeout);
}

Juliusz Chroboczek committed
1006
int
Juliusz Chroboczek committed
1007 1008
resize_receive_buffer(int size)
{
Juliusz Chroboczek committed
1009 1010
    unsigned char *new;

Juliusz Chroboczek committed
1011
    if(size <= receive_buffer_size)
Juliusz Chroboczek committed
1012
        return 0;
Juliusz Chroboczek committed
1013

Juliusz Chroboczek committed
1014 1015 1016 1017
    new = realloc(receive_buffer, size);
    if(new == NULL) {
        perror("realloc(receive_buffer)");
        return -1;
Juliusz Chroboczek committed
1018
    }
Juliusz Chroboczek committed
1019 1020 1021
    receive_buffer = new;
    receive_buffer_size = size;

Juliusz Chroboczek committed
1022
    return 1;
Juliusz Chroboczek committed
1023 1024
}

Juliusz Chroboczek committed
1025 1026 1027 1028 1029 1030
static void
sigexit(int signo)
{
    exiting = 1;
}

Juliusz Chroboczek committed
1031 1032 1033 1034 1035 1036
static void
sigdump(int signo)
{
    dumping = 1;
}

Juliusz Chroboczek committed
1037
static void
Juliusz Chroboczek committed
1038
sigreopening(int signo)
Juliusz Chroboczek committed
1039
{
Juliusz Chroboczek committed
1040
    reopening = 1;
Juliusz Chroboczek committed
1041 1042
}

Juliusz Chroboczek committed
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
static void
init_signals(void)
{
    struct sigaction sa;
    sigset_t ss;

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGHUP, &sa, NULL);

    sigemptyset(&ss);
    sa.sa_handler = sigexit;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);
Juliusz Chroboczek committed
1066

Juliusz Chroboczek committed
1067 1068 1069 1070 1071 1072
    sigemptyset(&ss);
    sa.sa_handler = SIG_IGN;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGPIPE, &sa, NULL);

Juliusz Chroboczek committed
1073 1074 1075 1076 1077
    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR1, &sa, NULL);
Juliusz Chroboczek committed
1078

Juliusz Chroboczek committed
1079
    sigemptyset(&ss);
Juliusz Chroboczek committed
1080
    sa.sa_handler = sigreopening;
Juliusz Chroboczek committed
1081 1082 1083 1084
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGUSR2, &sa, NULL);

Juliusz Chroboczek committed
1085 1086 1087 1088 1089 1090 1091
#ifdef SIGINFO
    sigemptyset(&ss);
    sa.sa_handler = sigdump;
    sa.sa_mask = ss;
    sa.sa_flags = 0;
    sigaction(SIGINFO, &sa, NULL);
#endif
Juliusz Chroboczek committed
1092 1093
}

Juliusz Chroboczek committed
1094
static void
Juliusz Chroboczek committed
1095
dump_route(FILE *out, struct babel_route *route)
Juliusz Chroboczek committed
1096 1097 1098 1099 1100 1101
{
    const unsigned char *nexthop =
        memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
        NULL : route->nexthop;
    char channels[100];

Juliusz Chroboczek committed
1102
    if(route->channels_len == 0) {
Juliusz Chroboczek committed
1103
        channels[0] = '\0';
Juliusz Chroboczek committed
1104
    } else {
Juliusz Chroboczek committed
1105 1106 1107
        int k, j = 0;
        snprintf(channels, 100, " chan (");
        j = strlen(channels);
Juliusz Chroboczek committed
1108
        for(k = 0; k < route->channels_len; k++) {
Juliusz Chroboczek committed
1109 1110
            if(k > 0)
                channels[j++] = ',';
Juliusz Chroboczek committed
1111
            snprintf(channels + j, 100 - j, "%u", (unsigned)route->channels[k]);
Juliusz Chroboczek committed
1112 1113 1114 1115 1116
            j = strlen(channels);
        }
        snprintf(channels + j, 100 - j, ")");
    }

Juliusz Chroboczek committed
1117
    fprintf(out, "%s%s%s metric %d (%d) refmetric %d id %s "
Matthieu Boutier committed
1118
            "seqno %d%s age %d via %s neigh %s%s%s%s\n",
Juliusz Chroboczek committed
1119
            format_prefix(route->src->prefix, route->src->plen),
Juliusz Chroboczek committed
1120 1121 1122
            route->src->src_plen > 0 ? " from " : "",
            route->src->src_plen > 0 ?
            format_prefix(route->src->src_prefix, route->src->src_plen) : "",
Juliusz Chroboczek committed
1123
            route_metric(route), route_smoothed_metric(route), route->refmetric,
Juliusz Chroboczek committed
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
            format_eui64(route->src->id),
            (int)route->seqno,
            channels,
            (int)(now.tv_sec - route->time),
            route->neigh->ifp->name,
            format_address(route->neigh->address),
            nexthop ? " nexthop " : "",
            nexthop ? format_address(nexthop) : "",
            route->installed ? " (installed)" :
            route_feasible(route) ? " (feasible)" : "");
}

Juliusz Chroboczek committed
1136
static void
Juliusz Chroboczek committed
1137
dump_xroute(FILE *out, struct xroute *xroute)
Juliusz Chroboczek committed
1138
{
Juliusz Chroboczek committed
1139
    fprintf(out, "%s%s%s metric %d (exported)\n",
Juliusz Chroboczek committed
1140
            format_prefix(xroute->prefix, xroute->plen),
Juliusz Chroboczek committed
1141 1142 1143
            xroute->src_plen > 0 ? " from " : "",
            xroute->src_plen > 0 ?
            format_prefix(xroute->src_prefix, xroute->src_plen) : "",
Juliusz Chroboczek committed
1144 1145 1146
            xroute->metric);
}

Juliusz Chroboczek committed
1147 1148 1149
static void
dump_tables(FILE *out)
{
Juliusz Chroboczek committed
1150
    struct neighbour *neigh;
Juliusz Chroboczek committed
1151
    struct xroute_stream *xroutes;
Juliusz Chroboczek committed
1152
    struct route_stream *routes;
Juliusz Chroboczek committed
1153 1154

    fprintf(out, "\n");
Juliusz Chroboczek committed
1155

Juliusz Chroboczek committed
1156
    fprintf(out, "My id %s seqno %d\n", format_eui64(myid), myseqno);
Juliusz Chroboczek committed
1157

Juliusz Chroboczek committed
1158
    FOR_ALL_NEIGHBOURS(neigh) {
Juliusz Chroboczek committed
1159
        fprintf(out, "Neighbour %s dev %s reach %04x ureach %04x "
Antonin Décimo committed
1160
                "rxcost %u txcost %d rtt %s rttcost %u chan %d%s.\n",
Juliusz Chroboczek committed
1161
                format_address(neigh->address),
Matthieu Boutier committed
1162
                neigh->ifp->name,
Juliusz Chroboczek committed
1163
                neigh->hello.reach,
Juliusz Chroboczek committed
1164
                neigh->uhello.reach,
Juliusz Chroboczek committed
1165 1166
                neighbour_rxcost(neigh),
                neigh->txcost,
Baptiste Jonglez committed
1167
                format_thousands(neigh->rtt),
Baptiste Jonglez committed
1168
                neighbour_rttcost(neigh),
Matthieu Boutier committed
1169 1170
                neigh->ifp->channel,
                if_up(neigh->ifp) ? "" : " (down)");
Juliusz Chroboczek committed
1171
    }
Juliusz Chroboczek committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182

    xroutes = xroute_stream();
    if(xroutes) {
        while(1) {
            struct xroute *xroute = xroute_stream_next(xroutes);
            if(xroute == NULL) break;
            dump_xroute(out, xroute);
        }
        xroute_stream_done(xroutes);
    }

Matthieu Boutier committed
1183
    routes = route_stream(ROUTE_ALL);
Juliusz Chroboczek committed
1184 1185 1186 1187 1188 1189 1190 1191
    if(routes) {
        while(1) {
            struct babel_route *route = route_stream_next(routes);
            if(route == NULL) break;
            dump_route(out, route);
        }
        route_stream_done(routes);
    }
Juliusz Chroboczek committed
1192

Juliusz Chroboczek committed
1193 1194 1195
    fflush(out);
}

Juliusz Chroboczek committed
1196
int
Juliusz Chroboczek committed
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
reopen_logfile()
{
    int lfd, rc;

    if(logfile == NULL)
        return 0;

    lfd = open(logfile, O_CREAT | O_WRONLY | O_APPEND, 0644);
    if(lfd < 0)
        return -1;

    fflush(stdout);
    fflush(stderr);

    rc = dup2(lfd, 1);
    if(rc < 0)
        return -1;

    rc = dup2(lfd, 2);
    if(rc < 0)
        return -1;

    if(lfd > 2)
        close(lfd);

    return 1;
}