local.c 7.74 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
Copyright (c) 2008 by Juliusz Chroboczek

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 <stdio.h>
#include <stdlib.h>
25
#include <string.h>
26 27
#include <unistd.h>
#include <errno.h>
28
#include <sys/time.h>
29

30
#include "babeld.h"
31
#include "interface.h"
32 33
#include "source.h"
#include "neighbour.h"
34
#include "kernel.h"
35 36 37 38
#include "xroute.h"
#include "route.h"
#include "util.h"
#include "local.h"
39
#include "version.h"
40

41 42 43 44 45 46
#ifdef NO_LOCAL_INTERFACE

int dummy;

#else

47 48 49 50
int local_server_socket = -1, local_sockets[MAX_LOCAL_SOCKETS];
int num_local_sockets = 0;
int local_server_port = -1;

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
int
local_read(int s)
{
    int rc;
    char buf[500];

    /* Ignore anything that comes in, except for EOF */
    rc = read(s, buf, 500);

    if(rc <= 0)
        return rc;

    return 1;
}

static int
write_timeout(int fd, const void *buf, int len)
{
    int n = 0, rc = 0;
    const char *b = buf;

    while(n < len) {
        rc = write(fd, b + n, len - n);
        if(rc < 0) {
            if(errno == EAGAIN || errno == EINTR) {
                rc = wait_for_fd(1, fd, 100);
                if(rc > 0) {
                    rc = write(fd, b + n, len - n);
                }
            }
        }
        if(rc > 0)
            n += rc;
        else
            break;
    }

    if(n >= len)
        return 1;
    else {
        if(rc >= 0)
            errno = EAGAIN;
        return -1;
    }
}

97
static void
98
local_notify_self_1(int s)
99
{
100
    char buf[512];
101
    char host[64];
102
    int rc;
103 104 105 106 107 108

    rc = gethostname(host, 64);

    if(rc < 0)
        strncpy(host, "alamakota", 64);

109
    rc = snprintf(buf, 512, "add self %.64s id %s\n",
110
                  host, format_eui64(myid));
111 112 113 114

    if(rc < 0 || rc >= 512)
        goto fail;

115
    rc = write_timeout(s, buf, rc);
116 117 118 119 120
    if(rc < 0)
        goto fail;
    return;

 fail:
121
    shutdown(s, 1);
122 123 124
    return;
}

125
static const char *
126 127 128 129 130 131 132 133 134 135
local_kind(int kind)
{
    switch(kind) {
    case LOCAL_FLUSH: return "flush";
    case LOCAL_CHANGE: return "change";
    case LOCAL_ADD: return "add";
    default: return "???";
    }
}

136 137
static void
local_notify_neighbour_1(int s, struct neighbour *neigh, int kind)
138
{
139
    char buf[512], rttbuf[64];
140 141
    int rc;

142 143
    rttbuf[0] = '\0';
    if(valid_rtt(neigh)) {
144 145
        rc = snprintf(rttbuf, 64, " rtt %s rttcost %d",
                      format_thousands(neigh->rtt), neighbour_rttcost(neigh));
146
        if(rc < 0 || rc >= 64)
147 148 149
            rttbuf[0] = '\0';
    }

150
    rc = snprintf(buf, 512,
151
                  "%s neighbour %lx address %s "
152
                  "if %s reach %04x rxcost %d txcost %d%s cost %d\n",
153
                  local_kind(kind),
154
                  /* Neighbours never move around in memory , so we can use the
155 156
                     address as a unique identifier. */
                  (unsigned long int)neigh,
157
                  format_address(neigh->address),
158
                  neigh->ifp->name,
159 160
                  neigh->reach,
                  neighbour_rxcost(neigh),
161
                  neighbour_txcost(neigh),
162
                  rttbuf,
163 164 165 166 167
                  neighbour_cost(neigh));

    if(rc < 0 || rc >= 512)
        goto fail;

168
    rc = write_timeout(s, buf, rc);
169 170 171 172 173
    if(rc < 0)
        goto fail;
    return;

 fail:
174
    shutdown(s, 1);
175 176 177 178
    return;
}

void
179 180 181 182 183 184 185 186 187
local_notify_neighbour(struct neighbour *neigh, int kind)
{
    int i;
    for(i = 0; i < num_local_sockets; i++)
        local_notify_neighbour_1(local_sockets[i], neigh, kind);
}

static void
local_notify_xroute_1(int s, struct xroute *xroute, int kind)
188 189 190
{
    char buf[512];
    int rc;
191 192 193 194
    const char *dst_prefix = format_prefix(xroute->prefix,
                                           xroute->plen);
    const char *src_prefix = format_prefix(xroute->src_prefix,
                                           xroute->src_plen);
195

196 197 198
    rc = snprintf(buf, 512, "%s xroute %s-%s prefix %s from %s metric %d\n",
                  local_kind(kind), dst_prefix, src_prefix,
                  dst_prefix, src_prefix, xroute->metric);
199

200 201 202
    if(rc < 0 || rc >= 512)
        goto fail;

203
    rc = write_timeout(s, buf, rc);
204 205 206 207 208
    if(rc < 0)
        goto fail;
    return;

 fail:
209
    shutdown(s, 1);
210 211 212 213
    return;
}

void
214 215 216 217 218 219 220 221 222
local_notify_xroute(struct xroute *xroute, int kind)
{
    int i;
    for(i = 0; i < num_local_sockets; i++)
        local_notify_xroute_1(local_sockets[i], xroute, kind);
}

static void
local_notify_route_1(int s, struct babel_route *route, int kind)
223 224 225
{
    char buf[512];
    int rc;
226 227 228 229
    const char *dst_prefix = format_prefix(route->src->prefix,
                                           route->src->plen);
    const char *src_prefix = format_prefix(route->src->src_prefix,
                                           route->src->src_plen);
230 231

    rc = snprintf(buf, 512,
232
                  "%s route %s-%lx-%s prefix %s from %s installed %s "
233
                  "id %s metric %d refmetric %d via %s if %s\n",
234
                  local_kind(kind),
235 236
                  dst_prefix, (unsigned long)route->neigh, src_prefix,
                  dst_prefix, src_prefix,
237
                  route->installed ? "yes" : "no",
238
                  format_eui64(route->src->id),
239
                  route_metric(route), route->refmetric,
240
                  format_address(route->neigh->address),
241
                  route->neigh->ifp->name);
242

243 244 245
    if(rc < 0 || rc >= 512)
        goto fail;

246
    rc = write_timeout(s, buf, rc);
247 248 249 250 251
    if(rc < 0)
        goto fail;
    return;

 fail:
252
    shutdown(s, 1);
253 254 255
    return;
}

256 257 258 259 260 261 262 263
void
local_notify_route(struct babel_route *route, int kind)
{
    int i;
    for(i = 0; i < num_local_sockets; i++)
        local_notify_route_1(local_sockets[i], route, kind);
}

264
void
265
local_notify_all_1(int s)
266
{
267
    int rc;
268
    struct neighbour *neigh;
269
    const char *header = "BABEL 0.0\n";
270
    char buf[512];
271
    struct xroute_stream *xroutes;
272
    struct route_stream *routes;
273

274
    rc = write_timeout(s, header, strlen(header));
275 276 277
    if(rc < 0)
        goto fail;

278 279 280 281 282 283 284
    rc = snprintf(buf, 512, "version %s\n", BABELD_VERSION);
    if(rc < 0 || rc >= 512)
        goto fail;
    rc = write_timeout(s, buf, rc);
    if(rc < 0)
        goto fail;

285
    local_notify_self_1(s);
286
    FOR_ALL_NEIGHBOURS(neigh) {
287
        local_notify_neighbour_1(s, neigh, LOCAL_ADD);
288
    }
289 290 291 292 293 294 295 296 297 298 299 300

    xroutes = xroute_stream();
    if(xroutes) {
        while(1) {
            struct xroute *xroute = xroute_stream_next(xroutes);
            if(xroute == NULL)
                break;
            local_notify_xroute_1(s, xroute, LOCAL_ADD);
        }
        xroute_stream_done(xroutes);
    }

301
    routes = route_stream(ROUTE_ALL);
302 303 304 305 306 307 308 309 310
    if(routes) {
        while(1) {
            struct babel_route *route = route_stream_next(routes);
            if(route == NULL)
                break;
            local_notify_route_1(s, route, LOCAL_ADD);
        }
        route_stream_done(routes);
    }
311

312
    rc = write_timeout(s, "done\n", 5);
313 314
    if(rc < 0)
        goto fail;
315 316 317
    return;

 fail:
318
    shutdown(s, 1);
319
    return;
320
}
321 322

#endif