/*
net.c -- most of the network code
Copyright (C) 1998-2005 Ivo Timmermans,
- 2000-2009 Guus Sliepen <guus@tinc-vpn.org>
+ 2000-2011 Guus Sliepen <guus@tinc-vpn.org>
2006 Scott Lamb <slamb@slamb.org>
This program is free software; you can redistribute it and/or modify
volatile bool running = false;
time_t now = 0;
+int contradicting_add_edge = 0;
+int contradicting_del_edge = 0;
/* Purge edges and subnets of unreachable nodes. Use carefully. */
for(snode = n->subnet_tree->head; snode; snode = snext) {
snext = snode->next;
s = snode->data;
- if(!tunnelserver)
- send_del_subnet(broadcast, s);
- subnet_del(n, s);
+ send_del_subnet(broadcast, s);
+ if(!strictsubnets)
+ subnet_del(n, s);
}
for(enode = n->edge_tree->head; enode; enode = enext) {
break;
}
- if(!enode)
+ if(!enode && (!strictsubnets || !n->subnet_tree->head))
+ /* in strictsubnets mode do not delete nodes with subnets */
node_del(n);
}
}
int result, i;
socklen_t len = sizeof(result);
vpn_packet_t packet;
+ static int errors = 0;
/* check input from kernel */
if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
if(read_packet(&packet)) {
+ errors = 0;
packet.priority = 0;
route(myself, &packet);
+ } else {
+ usleep(errors * 50000);
+ errors++;
+ if(errors > 10) {
+ logger(LOG_ERR, "Too many errors from %s, exiting!", device);
+ running = false;
+ }
}
}
if(FD_ISSET(c->socket, readset)) {
if(c->status.connecting) {
c->status.connecting = false;
- getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &result, &len);
+ getsockopt(c->socket, SOL_SOCKET, SO_ERROR, (void *)&result, &len);
if(!result)
finish_connecting(c);
else {
ifdebug(CONNECTIONS) logger(LOG_DEBUG,
"Error while connecting to %s (%s): %s",
- c->name, c->hostname, strerror(result));
+ c->name, c->hostname, sockstrerror(result));
closesocket(c->socket);
do_outgoing_connection(c);
continue;
#endif
if(r < 0) {
- if(errno != EINTR && errno != EAGAIN) {
- logger(LOG_ERR, "Error while waiting for input: %s",
- strerror(errno));
+ if(!sockwouldblock(sockerrno)) {
+ logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
dump_connections();
return 1;
}
-
- continue;
}
- check_network_activity(&readset, &writeset);
+ if(r > 0)
+ check_network_activity(&readset, &writeset);
if(do_purge) {
purge();
send_key_changed(broadcast, myself);
keyexpires = now + keylifetime;
}
+
+ if(contradicting_del_edge > 10 && contradicting_add_edge > 10) {
+ logger(LOG_WARNING, "Possible node with same Name as us!");
+
+ if(rand() % 3 == 0) {
+ logger(LOG_ERR, "Shutting down, check configuration of all nodes for duplicate Names!");
+ running = false;
+ break;
+ }
+
+ contradicting_add_edge = 0;
+ contradicting_del_edge = 0;
+ }
}
if(sigalrm) {
+ avl_node_t *node;
logger(LOG_INFO, "Flushing event queue");
expire_events();
+ for(node = connection_tree->head; node; node = node->next) {
+ connection_t *c = node->data;
+ send_ping(c);
+ }
sigalrm = false;
}
last_config_check = now;
+ /* If StrictSubnet is set, expire deleted Subnets and read new ones in */
+
+ if(strictsubnets) {
+ subnet_t *subnet;
+
+ for(node = subnet_tree->head; node; node = node->next) {
+ subnet = node->data;
+ subnet->expires = 1;
+ }
+
+ load_all_subnets();
+
+ for(node = subnet_tree->head; node; node = next) {
+ next = node->next;
+ subnet = node->data;
+ if(subnet->expires == 1) {
+ send_del_subnet(broadcast, subnet);
+ if(subnet->owner->status.reachable)
+ subnet_update(subnet->owner, subnet, false);
+ subnet_del(subnet->owner, subnet);
+ } else if(subnet->expires == -1) {
+ subnet->expires = 0;
+ } else {
+ send_add_subnet(broadcast, subnet);
+ if(subnet->owner->status.reachable)
+ subnet_update(subnet->owner, subnet, true);
+ }
+ }
+ }
+
/* Try to make outgoing connections */
try_outgoing_connections();