/**
 * Function called by transport telling us that a peer
 * disconnected.
 *
 * @param cls closure
 * @param peer the peer that disconnected
 */
static void
handle_transport_notify_disconnect (void *cls,
                                    const struct GNUNET_PeerIdentity *peer)
{
  struct Neighbour *n;

  if (0 == memcmp (peer,
                   &GSC_my_identity,
                   sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_break (0);
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Peer `%s' disconnected from us; received notification from transport.\n",
              GNUNET_i2s (peer));
  n = find_neighbour (peer);
  if (NULL == n)
  {
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s not found\n",
                GNUNET_i2s (peer));
    return;
  }
  free_neighbour (n);
}
/**
 * Transmit the given message to the given target.
 *
 * @param target peer that should receive the message (must be connected)
 * @param msg message to transmit
 * @param timeout by when should the transmission be done?
 */
void
GSC_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target,
                         const struct GNUNET_MessageHeader *msg,
                         struct GNUNET_TIME_Relative timeout)
{
  struct NeighbourMessageEntry *me;
  struct Neighbour *n;
  size_t msize;

  n = find_neighbour (target);
  if (NULL == n)
  {
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s not found\n",
                GNUNET_i2s (target));
    return;
  }
  msize = ntohs (msg->size);
  me = GNUNET_malloc (sizeof (struct NeighbourMessageEntry) + msize);
  me->deadline = GNUNET_TIME_relative_to_absolute (timeout);
  me->size = msize;
  memcpy (&me[1],
          msg,
          msize);
  GNUNET_CONTAINER_DLL_insert_tail (n->message_head,
                                    n->message_tail,
                                    me);
  n->queue_size++;
  process_queue (n);
}
/**
 * Function called by the transport for each received message.
 *
 * @param cls closure
 * @param peer (claimed) identity of the other peer
 * @param message the message
 */
static void
handle_transport_receive (void *cls,
                          const struct GNUNET_PeerIdentity *peer,
                          const struct GNUNET_MessageHeader *message)
{
  struct Neighbour *n;
  uint16_t type;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received message of type %u from `%s', demultiplexing.\n",
              (unsigned int) ntohs (message->type),
              GNUNET_i2s (peer));
  if (0 == memcmp (peer,
                   &GSC_my_identity,
                   sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_break (0);
    return;
  }
  n = find_neighbour (peer);
  if (NULL == n)
  {
    /* received message from peer that is not connected!? */
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s not found\n",
                GNUNET_i2s (peer));
    return;
  }
  type = ntohs (message->type);
  switch (type)
  {
  case GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY:
    GSC_KX_handle_ephemeral_key (n->kxinfo, message);
    break;
  case GNUNET_MESSAGE_TYPE_CORE_PING:
    GSC_KX_handle_ping (n->kxinfo, message);
    break;
  case GNUNET_MESSAGE_TYPE_CORE_PONG:
    GSC_KX_handle_pong (n->kxinfo, message);
    break;
  case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
    GSC_KX_handle_encrypted_message (n->kxinfo, message);
    break;
  case GNUNET_MESSAGE_TYPE_DUMMY:
    /*  Dummy messages for testing / benchmarking, just discard */
    break;
  default:
    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                _("Unsupported message of type %u (%u bytes) received from peer `%s'\n"),
                (unsigned int) type,
                (unsigned int) ntohs (message->size),
                GNUNET_i2s (peer));
    return;
  }
}
/**
 * Check if the given neighbour has excess bandwidth available.
 *
 * @param target neighbour to check
 * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not
 */
int
GSC_NEIGHBOURS_check_excess_bandwidth (const struct GNUNET_PeerIdentity *target)
{
  struct Neighbour *n;

  n = find_neighbour (target);
  if (NULL == n)
  {
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s not found\n",
                GNUNET_i2s (target));
    return GNUNET_SYSERR;
  }
  return n->has_excess_bandwidth;
}
/**
 * Check how many messages are queued for the given neighbour.
 *
 * @param target neighbour to check
 * @return number of items in the message queue
 */
unsigned int
GSC_NEIGHBOURS_get_queue_size (const struct GNUNET_PeerIdentity *target)
{
  struct Neighbour *n;

  n = find_neighbour (target);
  if (NULL == n)
  {
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s not found\n",
                GNUNET_i2s (target));
    return UINT_MAX;
  }
  return n->queue_size;
}
Exemplo n.º 6
0
/* We got a Hello or IHU from a neighbour, update its entry. */
int
update_neighbour(struct in6_addr *from, struct interface *interface,
                 unsigned int ihu, unsigned short interval_or_rxcost)
{
    int i = find_neighbour(interface, from, !ihu);
    if(i < 0)
        return 0;

    if(ihu) {
        neighbours[i].rxcost = interval_or_rxcost;
    } else {
        struct timeval now;
        int interval = interval_or_rxcost;
        gettime(&now);
        /* We'll expire this neighbour if we miss 3 Hellos in a row. */
        timeval_add_msec(&neighbours[i].timeout, &now,
                         3 * interval * 10 + rand() % (interval * 5));
    }
    return 1;
}
Exemplo n.º 7
0
/* We just got an Update for the default route. */
int
update_selected_route(struct interface *interface, struct in6_addr *nexthop,
                      short interval, int metric)
{
    struct timeval now;
    int n = find_neighbour(interface, nexthop, 0);

    if(n < 0)
        return 0;

    metric += MAX(link_cost, neighbours[n].rxcost);

    gettime(&now);

    if(selected_nexthop_metric >= INFINITY ||
       interface != selected_interface ||
       memcmp(nexthop, &selected_nexthop, sizeof(selected_nexthop)) != 0) {
        int rc;
        if(metric >= INFINITY ||
           (metric >= selected_nexthop_metric + 32 &&
            timeval_compare(&now, &selected_nexthop_timeout) < 0)) {
            /* Our currently selected route is just as good or better. */
            return 0;
        }

        rc = install_default_route(interface->ifindex, nexthop);
        if(rc < 0) {
            perror("install_default_route");
            return -1;
        }
        selected_interface = interface;
        memcpy(&selected_nexthop, nexthop, sizeof(selected_nexthop));
    }

    selected_nexthop_metric = metric;
    /* Expire this route when we lose 3 updates in a row. */
    timeval_add_msec(&selected_nexthop_timeout, &now,
                     3 * interval * 10 + rand() % (interval * 5));

    return 1;
}
/**
 * One of our neighbours has excess bandwidth, remember this.
 *
 * @param cls NULL
 * @param pid identity of the peer with excess bandwidth
 */
static void
handle_transport_notify_excess_bw (void *cls,
                                   const struct GNUNET_PeerIdentity *pid)
{
  struct Neighbour *n;

  n = find_neighbour (pid);
  if (NULL == n)
  {
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s not found\n",
                GNUNET_i2s (pid));
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Peer %s has excess bandwidth available\n",
              GNUNET_i2s (pid));
  n->has_excess_bandwidth = GNUNET_YES;
  GSC_SESSIONS_solicit (pid);
}
/**
 * Function called by transport to notify us that
 * a peer connected to us (on the network level).
 *
 * @param cls closure
 * @param peer the peer that connected
 */
static void
handle_transport_notify_connect (void *cls,
                                 const struct GNUNET_PeerIdentity *peer)
{
  struct Neighbour *n;

  if (0 == memcmp (peer,
                   &GSC_my_identity,
                   sizeof (struct GNUNET_PeerIdentity)))
  {
    GNUNET_break (0);
    return;
  }
  n = find_neighbour (peer);
  if (NULL != n)
  {
    /* duplicate connect notification!? */
    GNUNET_break (0);
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                "Peer %s exists already\n",
                GNUNET_i2s (peer));
    return;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received connection from `%s'.\n",
              GNUNET_i2s (peer));
  n = GNUNET_new (struct Neighbour);
  n->peer = *peer;
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_put (neighbours,
                                                    &n->peer,
                                                    n,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  GNUNET_STATISTICS_set (GSC_stats,
                         gettext_noop ("# neighbour entries allocated"),
                         GNUNET_CONTAINER_multipeermap_size (neighbours),
                         GNUNET_NO);
  n->kxinfo = GSC_KX_start (peer);
}
Exemplo n.º 10
0
void calculate_indices(struct aiMesh mesh, model* m)
{
	uint32_t a, b;

	m->n_indices = mesh.mNumFaces *6;
	
	m->indices = malloc(sizeof(uint32_t)*m->n_indices);
	
	if(mesh.mFaces != NULL){
		int n = 0;
		for(uint32_t i = 0; i < mesh.mNumFaces; i++){
			for(uint32_t j = 0; j < mesh.mFaces[i].mNumIndices;
					j++){
				a = mesh.mFaces[i].mIndices[j];
				b = mesh.mFaces[i].mIndices[(j+1) % 3];
				m->indices[n + 2*j] = a;
				m->indices[n + 2*j + 1] = find_neighbour(a, b);
			}
			n += 6;
		}

	}
}
Exemplo n.º 11
0
void Map::generate_level(int map_width, int map_height, int num_connections)
{
	// Clean up any possible earlier map:
	delete[] tiles;
	
	// Allocate map array and setup variables:
	width = map_width;
	height = map_height;
	tiles = new int[width * height];
	eggs_left = 0;

	// Random generate map:
	int x, y, center_x, center_y, num_tiles, i;
	
	// 1. clear map with walls.
	for (y=0; y<height; y++)
		for (x=0; x<width; x++)
			tiles[x + y*width] = 4;

	// 2. make gaps in all four directions at starting point in map.
	center_x = width/2;
	center_y = height/2;
	
	tiles[center_x   + center_y     * width] = 0;
	tiles[center_x-1 + center_y     * width] = 1;
	tiles[center_x+1 + center_y     * width] = 1;
	tiles[center_x   + (center_y-1) * width] = 1;
	tiles[center_x   + (center_y+1) * width] = 1;

	// 3. build tunnels in level
	num_tiles = width * height;
	std::vector<int> tunnel_x[4];
	std::vector<int> tunnel_y[4];
	for (i=0; i<4; i++)
	{
		tunnel_x[i].resize(num_tiles);
		tunnel_y[i].resize(num_tiles);
	}

	// Set the four tunnel starting points:
	tunnel_x[0][0] = center_x;
	tunnel_y[0][0] = center_y - 2;
	tunnel_x[1][0] = center_x;
	tunnel_y[1][0] = center_y + 2;
	tunnel_x[2][0] = center_x - 2;
	tunnel_y[2][0] = center_y;
	tunnel_x[3][0] = center_x + 2;
	tunnel_y[3][0] = center_y;

	// Mark beginning tiles as tunnel:
	for (i=0; i<4; i++)
		tiles[tunnel_x[i][0] + tunnel_y[i][0]*width] = 1;

	// Start creating the tunnels. We do this up to num_tiles times, since this is the
	// theoretically maximum length any tunnel could possibly have.
	for (int pos=1; pos<num_tiles; pos++)
	{
		// For each round, the tunnel finds a neighbour tile that it can move into.
		int filled_level = 0;
		for (int tun=0; tun<4; tun++)
		{
			// Find free neighbours to this tile. Update which one was chosen
			// to the current position in the tunnel_x and tunnel_y arrays.
			if (find_neighbour(
				tunnel_x[tun][pos-1],
				tunnel_y[tun][pos-1],
				&tunnel_x[tun][pos],
				&tunnel_y[tun][pos])==false)
			{
				// Try and figure out if we moved into a total dead end.
				bool total_dead_end = true;
				for (int pos2=pos-2; pos2>=0; pos2--)
				{
					if (find_neighbour(
						tunnel_x[tun][pos2],
						tunnel_y[tun][pos2],
						&tunnel_x[tun][pos],
						&tunnel_y[tun][pos]))
					{
						total_dead_end = false;
						break;
					}
				}

				// If we moved into a total dead end, this tunnel can move no
				// further.
				if (total_dead_end)
				{
					tunnel_x[tun][pos] = tunnel_x[tun][pos-1];
					tunnel_y[tun][pos] = tunnel_y[tun][pos-1];
					filled_level++;
				}
			}
			
			// Mark newly found tile as egg:
			tiles[tunnel_x[tun][pos] + tunnel_y[tun][pos]*width] = 1;
		}
		
		// All four tunnels reached a dead end. We're done tunneling.
		if (filled_level == 4) break;
	}
	
	// 4. connect gaps random in the tunnels:
	for (i=0; i<num_connections; i++)
	{
		int x = rand()%(width/2-3);
		int y = rand()%(height/2-3);
		
		x *= 2; y *= 2;
		x += 3; y += 3;
		
		switch (rand()%4)
		{
		case 0:
			tiles[x + (y-1)*width] = 1;
			break;
		case 1:
			tiles[x + (y+1)*width] = 1;
			break;
		case 2:
			tiles[(x-1) + y*width] = 1;
			break;
		case 3:
			tiles[(x+1) + y] = 1;
			break;
		}
	}

	// Random generation is complete.
	
	// Now change the map wall tiles to correct sprite frame:
	// (we got different images depending which walls are next to a wall)
	for (y=0; y<height; y++)
	{
		for (x=0; x<width; x++)
		{
			// If tile is not a wall, dont change tile sprite frame.
			if (tiles[x + y*width] <= 2) continue;

			int new_image = 0; 
			if (x>0	       && tiles[(x-1) + y*width] > 3) new_image |= 1; // left flag
			if (x<width-1  && tiles[(x+1) + y*width] > 3) new_image |= 2; // right flag
			if (y>0	       && tiles[x + (y-1)*width] > 3) new_image |= 4; // up flag
			if (y<height-1 && tiles[x + (y+1)*width] > 3) new_image |= 8; // down flag

			tiles[x + y*width] = new_image+4;
		}
	}
	
	// Place powerups in each corner of map:
	tiles[1         + 1*width] = 2;
	tiles[(width-2) + 1*width] = 2;
	tiles[1         + (height-2)*width] = 2;
	tiles[(width-2) + (height-2)*width] = 2;

	// Count the number of eggs
	eggs_left = 0;
	for (y=0; y<height; y++)
		for (x=0; x<width; x++)       
			if ((tiles[x + y*width] == 1) || (tiles[x + y*width] == 2))
				eggs_left++;
	
}
Exemplo n.º 12
0
std::shared_ptr<Hex> Hex_map::find_neighbour_ptr(Coord hex, Coord direction) // podstawowa
{
    auto neigbour_coord = find_neighbour(hex, direction);
    return map[neigbour_coord.x][neigbour_coord.y].second;
}
Exemplo n.º 13
0
Coord Hex_map::find_neighbour(std::shared_ptr<Hex> hex, Coord direction)
{
    return find_neighbour(hex->get_coord(), direction);
}
Exemplo n.º 14
0
Coord Hex_map::find_neighbour(Hex hex, Coord direction)
{
    return find_neighbour(hex.get_coord(), direction);
}
Exemplo n.º 15
0
int
parse_packet(const unsigned char *buf, int buflen,
             struct sockaddr_in6 *from, int unicast,
             struct interface *interface)
{
    unsigned char id[4];
    unsigned int eid = 42;      /* silence gcc */
    int have_id = 0;
    int i = 0, rc;
    int recompute = 0;

    if(debug_level >= 3)
        debugf("Received %d bytes.\n", buflen);

    while(i < buflen) {
        unsigned const char *tlv = buf + i;
        int type, bodylen;

        if(buflen - i < 4) {
            fprintf(stderr, "Received truncated TLV.\n");
            goto fail;
        }

        DO_NTOHS(type, tlv);
        DO_NTOHS(bodylen, tlv + 2);
        if(buflen - i < 4 + bodylen) {
            fprintf(stderr, "Received truncated TLV.\n");
            goto fail;
        }

        switch(type) {
        case 1: {
            debugf("   REQ-NETWORK-STATE\n");
            int i;
            buffer_network_state(from, NULL);
            for(i = 0; i < numnodes; i++)
                buffer_node_state(&nodes[i], 0, from, NULL);
            break;
        }
        case 2: {
            struct node *node;
            if(bodylen < 4) {
                fprintf(stderr, "Truncated REQ-NODE-STATE\n");
                goto fail;
            }
            debugf("   REQ-NODE-STATE %s\n", format_32(tlv + 4));
            node = find_node(tlv + 4, 0);
            if(node)
                buffer_node_state(node, 1, from, NULL);
            break;
        }
        case 3: {
            struct neighbour *neigh;
            if(bodylen < 8) {
                fprintf(stderr, "Truncated NODE-ENDPOINT.\n");
                break;
            }
            if(have_id) {
                fprintf(stderr, "Duplicate NODE-ENDPOINT.\n");
                break;
            }
            memcpy(id, tlv + 4, 4);
            DO_NTOHL(eid, tlv + 8);
            debugf("   NODE-ENDPOINT %s %u\n", format_32(id), eid);
            if(id_eq(id, myid)) {
                fprintf(stderr, "Node id collision.\n");
                goto fail;
            }
            have_id = 1;
            if(unicast) {
                neigh = find_neighbour(interface, id, eid, from);
                if(neigh && unicast)
                    neigh->last_contact = now;
            }
            break;
        }
        case 4: {
            int rc;
            unsigned char h[8];
            struct neighbour *neigh = NULL;
            struct timespec t;

            if(have_id)
                neigh = find_neighbour(interface, id, eid, NULL);

            if(bodylen < 8) {
                fprintf(stderr, "Truncated NETWORK-STATE.\n");
                goto fail;
            }

            rc = network_hash(h);
            if(rc < 0) {
                fprintf(stderr, "Eek!\n");
                goto fail;
            }

            if(memcmp(h, tlv + 4, 8) == 0) {
                debugf("   NETWORK-STATE %s (consistent)\n",
                       format_64(tlv + 4));
                if(neigh)
                    neigh->last_contact = now;
                trickle_reset(&interface->trickle, 1);
                break;
            }

            debugf("   NETWORK-STATE %s (inconsistent, %s)\n",
                   format_64(tlv + 4), format_64(h));
            /* But don't reset Trickle. */

            ts_add_msec(&t, &interface->last_request_sent, HNCP_I_min);
            if(ts_compare(&now, &t) >= 0) {
                interface->last_request_sent = now;
                debugf("-> REQ-NETWORK-STATE\n");
                buffer_tlv(1, NULL, 0, from, NULL);
            }
            break;
        }
        case 5: {
            struct node *node;
            unsigned int seqno;
            int msecs, mine;
            int datalen = bodylen - 20;

            if(bodylen < 20) {
                fprintf(stderr, "Truncated NODE-STATE.\n");
                goto fail;
            }

            if(!have_id) {
                fprintf(stderr, "NODE-STATE with no NODE-ENDPOINT.\n");
            }

            DO_NTOHL(seqno, tlv + 8);
            DO_NTOHL(msecs, tlv + 12);

            debugf("   NODE-STATE %s %d %d", format_32(tlv + 4), seqno, msecs);

            mine = id_eq(tlv + 4, myid);
            if(mine)
                debugf(" (mine)");

            node = find_node(tlv + 4, 0);

            if(node && (seqno - node->seqno) & 0x80000000) {
                debugf(" (older)\n");
            } else if(!node || seqno != node->seqno ||
                      memcmp(tlv + 16, node->datahash, 8) != 0) {
                debugf(" (newer%s, %s)\n",
                       datalen ? ", data" : "", format_64(tlv + 16));

                if(mine) {
                    fprintf(stderr,
                            "Duplicate node identifier -- reclaiming.\n");
                    node->seqno = seqno + 42;
                    break;
                }

                if(datalen) {
                    unsigned char *new_data;
                    unsigned char h[8];
                    int rc;

                    node_hash(h, tlv + 24, datalen);
                    if(memcmp(h, tlv + 16, 8) != 0) {
                        fprintf(stderr, "Corrupt hash.\n");
                        goto fail;
                    }

                    if(!node)
                        node = find_node(tlv + 4, 1);
                    if(!node) {
                        fprintf(stderr, "Couldn't create node.\n");
                        goto fail;
                    }

                    new_data = realloc(node->data, datalen);
                    if(new_data == NULL) {
                        fprintf(stderr, "Eek!\n");
                        goto fail;
                    }
                    node->interface = interface;
                    node->seqno = seqno;
                    ts_add_msec(&node->orig_time, &now, msecs + 1);
                    node->data = new_data;
                    memcpy(node->data, tlv + 24, datalen);
                    node->datalen = datalen;
                    memcpy(node->datahash, tlv + 16, 8);
                    rc = parse_node_state(node);
                    if(rc < 0)
                        fprintf(stderr, "Couldn't parse node state.\n");
                    else
                        trickle_reset_all();
                    recompute = 1;
                } else {
                    struct neighbour *neigh = NULL;
                    if(have_id)
                        neigh = find_neighbour(interface, id, eid, from);
                    if(neigh) {
                        debugf("-> REQ-NODE-STATE %s\n", format_32(tlv + 4));
                        buffer_tlv(2, tlv + 4, 4, from, NULL);
                    } else
                        fprintf(stderr, "No neighbour to send request to.\n");
                }
            } else {
                debugf(" (consistent)\n");
            }
            break;
        }
        default:
            if(debug_level >= 3)
                debugf("   %d: %d\n", type, bodylen);
            break;
            break;
        }
        i += 4 + bodylen;
        i += -i & 3;
    }

    rc = 1;
    goto done;

 fail:
    rc = -1;

 done:
    if(recompute) {
        int r;
        silly_walk(find_node(myid, 0));
        r = prefix_assignment(1);
        if(r > 0)
            republish(0, 1);
    }
    return rc;
}
Exemplo n.º 16
0
int
main(int argc, char **argv)
{
    int i, opt, rc;
    int sock;
    struct timeval now;

    gettime(&now);

    inet_pton(AF_INET6, "ff02::1:6", &babel_group);
    babel_port = 6696;

    srand(now.tv_sec ^ now.tv_usec);

    while(1) {
        opt = getopt(argc, argv, "p:u:h:c:");
        if(opt < 0)
            break;

        switch(opt) {
        case 'p':               /* prefix */
            if(have_prefix)
                goto usage;
            rc = inet_pton(AF_INET6, optarg, &myprefix);
            if(rc != 1)
                goto usage;
            have_prefix = 1;
            break;
        case 'u':               /* update interval */
            update_interval = atoi(optarg);
            if(update_interval <= 0)
                goto usage;
            break;
        case 'h':               /* hello interval */
            hello_interval = atoi(optarg);
            if(hello_interval <= 0)
                goto usage;
            break;
        case 'c':               /* link cost */
            link_cost = atoi(optarg);
            if(link_cost <= 0)
                goto usage;
            break;
        default:
            goto usage;
        }
    }

    if(!have_prefix)
        fprintf(stderr, "Warning: you didn't ask me to announce a prefix.\n");

    if(argc - optind > MAXINTERFACES) {
        fprintf(stderr, "Too many interfaces.\n");
        exit(1);
    }

    for(i = 0; i < argc - optind; i++) {
        int index;

        index = if_nametoindex(argv[optind + i]);
        if(index <= 0) {
            fprintf(stderr, "Unknown interface %s\n", argv[i]);
            exit(1);
        }
        memset(&interfaces[i], 0, sizeof(interfaces[i]));
        interfaces[i].ifindex = index;
        interfaces[i].ifname = argv[optind + i];
        rc = get_local_address(interfaces[i].ifindex, &interfaces[i].address);
        if(rc < 0) {
            perror("get_local_address");
            fprintf(stderr, "Continuing anyway -- "
                    "won't perform reachibility detection "
                    "on interface %s.\n", interfaces[i].ifname);
        }
        interfaces[i].seqno = rand() & 0xFFFF;
    }
    numinterfaces = argc - optind;

    random_eui64(my_router_id);
    myseqno = rand() & 0xFFFF;

    sock = babel_socket(babel_port);
    if(sock < 0) {
        perror("babel_socket");
        exit(1);
    }

    for(i = 0; i < numinterfaces; i++) {
        rc = join_group(sock, interfaces[i].ifindex, &babel_group);
        if(rc < 0) {
            perror("setsockopt(IPV6_JOIN_GROUP)");
            exit(1);
        }
    }

    catch_signals(sigexit);

    while(!exiting) {
        struct sockaddr_in6 sin6;
        unsigned char buf[BUF_SIZE];
        struct timeval tv, update, zerotv = {0, 0};
        fd_set readfds;
        int hello_count = 0;

        /* Compute when to wake up. */
        gettime(&now);
        timeval_add_msec(&tv, &last_hello, hello_interval * 700 + rand() % 300);
        timeval_add_msec(&update, &last_update,
                         update_interval * 700 + rand() % 300);
        timeval_min(&tv, &update);

        if(selected_nexthop_metric < INFINITY) {
            int n = find_neighbour(selected_interface, &selected_nexthop, 0);
            assert(n >= 0);
            timeval_min(&tv, &neighbours[n].timeout);
            timeval_min(&tv, &selected_nexthop_timeout);
        }

        if(timeval_compare(&tv, &now) > 0)
            timeval_minus(&tv, &tv, &now);
        else
            tv = zerotv;

        FD_ZERO(&readfds);
        FD_SET(sock, &readfds);

        rc = select(sock + 1, &readfds, NULL, NULL, &tv);
        if(rc < 0 && errno != EINTR) {
            perror("select");
            nap(1000);
            continue;
        }

        if(rc > 0) {
            /* Oh good, a packet. */
            socklen_t sin6len = sizeof(sin6);
            rc = recvfrom(sock, buf, BUF_SIZE, 0,
                          (struct sockaddr*)&sin6, &sin6len);

            if(rc < 0 || rc >= BUF_SIZE) {
                if(rc < 0 && errno != EAGAIN) {
                    perror("recv");
                    nap(100);
                }
                continue;
            }

            if(sin6.sin6_family != PF_INET6) {
                fprintf(stderr, "Received unexpected packet in family %d.\n",
                        sin6.sin6_family);
                nap(100);
                continue;
            }

            i = find_interface(sin6.sin6_scope_id);
            if(i < 0) {
                fprintf(stderr, "Received packet on unknown interface %d.\n",
                        sin6.sin6_scope_id);
                nap(100);
                continue;
            }
            handle_packet(sock, buf, rc, &interfaces[i], &sin6.sin6_addr);
        }

        gettime(&now);

        if(selected_nexthop_metric < INFINITY) {
            int n = find_neighbour(selected_interface, &selected_nexthop, 0);
            assert(n >= 0);

            if(neighbour_expired(n, &now)) {
                /* Expire neighbour. */
                flush_default_route();
                delete_neighbour(n);
            } else if(timeval_compare(&now, &selected_nexthop_timeout) > 0) {
                /* Expire route. */
                flush_default_route();
            }
            /* Send a request? */
        }

        /* Is it time to send hellos? */
        if(timeval_minus_msec(&now, &last_hello) > hello_interval * 700) {
            for(i = 0; i < numinterfaces; i++)
                send_hello(sock, &interfaces[i]);
            last_hello = now;
            hello_count++;
            /* Make an expiry pass every ten hellos. */
            if(hello_count >= 10) {
                expire_neighbours();
                hello_count = 0;
            }
        }

        /* Is it time to send an update? */
        if(timeval_minus_msec(&now, &last_update) > update_interval * 700) {
            for(i = 0; i < numinterfaces; i++)
                send_update(sock, &interfaces[i], 0);
            last_update = now;
        }
    }

    /* Send a bunch of retractions. */
    for(i = 0; i < numinterfaces; i++)
        send_update(sock, &interfaces[i], 1);

    flush_default_route();

    return 0;

 usage:
    fprintf(stderr,
            "Usage: sbabeld "
            "[-p prefix] [-u interval] [-h interval] [-c cost] interface...\n");
    return 1;
}