C99 extravaganza.
This commit is contained in:
parent
ff306f0cda
commit
0b8b23e0dd
24 changed files with 131 additions and 328 deletions
|
@ -91,7 +91,7 @@ void connection_add(connection_t *c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void connection_del(connection_t *c) {
|
void connection_del(connection_t *c) {
|
||||||
for(list_node_t *node = connection_list->head; node; node = node->next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
if(node->data == c) {
|
if(node->data == c) {
|
||||||
list_delete_node(connection_list, node);
|
list_delete_node(connection_list, node);
|
||||||
return;
|
return;
|
||||||
|
@ -100,9 +100,7 @@ void connection_del(connection_t *c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_connections(connection_t *cdump) {
|
bool dump_connections(connection_t *cdump) {
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
send_request(cdump, "%d %d %s %s %x %d %x",
|
send_request(cdump, "%d %d %s %s %x %d %x",
|
||||||
CONTROL, REQ_DUMP_CONNECTIONS,
|
CONTROL, REQ_DUMP_CONNECTIONS,
|
||||||
c->name, c->hostname, c->options, c->socket,
|
c->name, c->hostname, c->options, c->socket,
|
||||||
|
|
|
@ -99,15 +99,12 @@ bool control_h(connection_t *c, const char *request) {
|
||||||
|
|
||||||
case REQ_DISCONNECT: {
|
case REQ_DISCONNECT: {
|
||||||
char name[MAX_STRING_SIZE];
|
char name[MAX_STRING_SIZE];
|
||||||
connection_t *other;
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1)
|
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1)
|
||||||
return control_return(c, REQ_DISCONNECT, -1);
|
return control_return(c, REQ_DISCONNECT, -1);
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, other, connection_list) {
|
||||||
next = node->next;
|
|
||||||
other = node->data;
|
|
||||||
if(strcmp(other->name, name))
|
if(strcmp(other->name, name))
|
||||||
continue;
|
continue;
|
||||||
terminate_connection(other, other->status.active);
|
terminate_connection(other, other->status.active);
|
||||||
|
|
13
src/edge.c
13
src/edge.c
|
@ -107,16 +107,9 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_edges(connection_t *c) {
|
bool dump_edges(connection_t *c) {
|
||||||
splay_node_t *node, *node2;
|
for splay_each(node_t, n, node_tree) {
|
||||||
node_t *n;
|
for splay_each(edge_t, e, n->edge_tree) {
|
||||||
edge_t *e;
|
char *address = sockaddr2hostname(&e->address);
|
||||||
char *address;
|
|
||||||
|
|
||||||
for(node = node_tree->head; node; node = node->next) {
|
|
||||||
n = node->data;
|
|
||||||
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
|
||||||
e = node2->data;
|
|
||||||
address = sockaddr2hostname(&e->address);
|
|
||||||
send_request(c, "%d %d %s %s %s %x %d",
|
send_request(c, "%d %d %s %s %s %x %d",
|
||||||
CONTROL, REQ_DUMP_EDGES,
|
CONTROL, REQ_DUMP_EDGES,
|
||||||
e->from->name, e->to->name, address,
|
e->from->name, e->to->name, address,
|
||||||
|
|
66
src/graph.c
66
src/graph.c
|
@ -68,26 +68,19 @@
|
||||||
static void mst_kruskal(void) {
|
static void mst_kruskal(void) {
|
||||||
/* Clear MST status on connections */
|
/* Clear MST status on connections */
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head; node; node = node->next) {
|
for list_each(connection_t, c, connection_list)
|
||||||
connection_t *c = node->data;
|
|
||||||
c->status.mst = false;
|
c->status.mst = false;
|
||||||
}
|
|
||||||
|
|
||||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Running Kruskal's algorithm:");
|
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Running Kruskal's algorithm:");
|
||||||
|
|
||||||
/* Clear visited status on nodes */
|
/* Clear visited status on nodes */
|
||||||
|
|
||||||
for(splay_node_t *node = node_tree->head; node; node = node->next) {
|
for splay_each(node_t, n, node_tree)
|
||||||
node_t *n = node->data;
|
|
||||||
n->status.visited = false;
|
n->status.visited = false;
|
||||||
}
|
|
||||||
|
|
||||||
/* Add safe edges */
|
/* Add safe edges */
|
||||||
|
|
||||||
for(splay_node_t *node = edge_weight_tree->head, *next; node; node = next) {
|
for splay_each(edge_t, e, edge_weight_tree) {
|
||||||
next = node->next;
|
|
||||||
edge_t *e = node->data;
|
|
||||||
|
|
||||||
if(!e->reverse || (e->from->status.visited && e->to->status.visited))
|
if(!e->reverse || (e->from->status.visited && e->to->status.visited))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -110,19 +103,11 @@ static void mst_kruskal(void) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void sssp_bfs(void) {
|
static void sssp_bfs(void) {
|
||||||
splay_node_t *node, *to;
|
list_t *todo_list = list_alloc(NULL);
|
||||||
edge_t *e;
|
|
||||||
node_t *n;
|
|
||||||
list_t *todo_list;
|
|
||||||
list_node_t *from, *todonext;
|
|
||||||
bool indirect;
|
|
||||||
|
|
||||||
todo_list = list_alloc(NULL);
|
|
||||||
|
|
||||||
/* Clear visited status on nodes */
|
/* Clear visited status on nodes */
|
||||||
|
|
||||||
for(node = node_tree->head; node; node = node->next) {
|
for splay_each(node_t, n, node_tree) {
|
||||||
n = node->data;
|
|
||||||
n->status.visited = false;
|
n->status.visited = false;
|
||||||
n->status.indirect = true;
|
n->status.indirect = true;
|
||||||
n->distance = -1;
|
n->distance = -1;
|
||||||
|
@ -140,14 +125,13 @@ static void sssp_bfs(void) {
|
||||||
|
|
||||||
/* Loop while todo_list is filled */
|
/* Loop while todo_list is filled */
|
||||||
|
|
||||||
for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */
|
for list_each(node_t, n, todo_list) { /* "n" is the node from which we start */
|
||||||
n = from->data;
|
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Examining edges from %s", n->name);
|
||||||
|
|
||||||
if(n->distance < 0)
|
if(n->distance < 0)
|
||||||
abort();
|
abort();
|
||||||
|
|
||||||
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
|
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
|
||||||
e = to->data;
|
|
||||||
|
|
||||||
if(!e->reverse)
|
if(!e->reverse)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -168,7 +152,7 @@ static void sssp_bfs(void) {
|
||||||
of nodes behind it.
|
of nodes behind it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
bool indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
||||||
|
|
||||||
if(e->to->status.visited
|
if(e->to->status.visited
|
||||||
&& (!e->to->status.indirect || indirect)
|
&& (!e->to->status.indirect || indirect)
|
||||||
|
@ -183,34 +167,23 @@ static void sssp_bfs(void) {
|
||||||
e->to->options = e->options;
|
e->to->options = e->options;
|
||||||
e->to->distance = n->distance + 1;
|
e->to->distance = n->distance + 1;
|
||||||
|
|
||||||
if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
|
if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN))
|
||||||
)
|
|
||||||
update_node_udp(e->to, &e->address);
|
update_node_udp(e->to, &e->address);
|
||||||
|
|
||||||
list_insert_tail(todo_list, e->to);
|
list_insert_tail(todo_list, e->to);
|
||||||
}
|
}
|
||||||
|
|
||||||
todonext = from->next;
|
next = node->next; /* Because the list_insert_tail() above could have added something extra for us! */
|
||||||
list_delete_node(todo_list, from);
|
list_delete_node(todo_list, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_free(todo_list);
|
list_free(todo_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_reachability(void) {
|
static void check_reachability(void) {
|
||||||
splay_node_t *node, *next;
|
|
||||||
node_t *n;
|
|
||||||
char *name;
|
|
||||||
char *address, *port;
|
|
||||||
char *envp[7];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* Check reachability status. */
|
/* Check reachability status. */
|
||||||
|
|
||||||
for(node = node_tree->head; node; node = next) {
|
for splay_each(node_t, n, node_tree) {
|
||||||
next = node->next;
|
|
||||||
n = node->data;
|
|
||||||
|
|
||||||
if(n->status.visited != n->status.reachable) {
|
if(n->status.visited != n->status.reachable) {
|
||||||
n->status.reachable = !n->status.reachable;
|
n->status.reachable = !n->status.reachable;
|
||||||
n->last_state_change = time(NULL);
|
n->last_state_change = time(NULL);
|
||||||
|
@ -242,6 +215,11 @@ static void check_reachability(void) {
|
||||||
if(timeout_initialized(&n->mtuevent))
|
if(timeout_initialized(&n->mtuevent))
|
||||||
event_del(&n->mtuevent);
|
event_del(&n->mtuevent);
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
char *address;
|
||||||
|
char *port;
|
||||||
|
char *envp[7];
|
||||||
|
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||||
|
@ -253,16 +231,14 @@ static void check_reachability(void) {
|
||||||
|
|
||||||
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
|
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
|
||||||
|
|
||||||
xasprintf(&name,
|
xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
|
||||||
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
|
|
||||||
n->name);
|
|
||||||
execute_script(name, envp);
|
execute_script(name, envp);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
free(address);
|
free(address);
|
||||||
free(port);
|
free(port);
|
||||||
|
|
||||||
for(i = 0; i < 6; i++)
|
for(int i = 0; i < 6; i++)
|
||||||
free(envp[i]);
|
free(envp[i]);
|
||||||
|
|
||||||
subnet_update(n, NULL, n->status.reachable);
|
subnet_update(n, NULL, n->status.reachable);
|
||||||
|
|
34
src/list.c
34
src/list.c
|
@ -26,9 +26,7 @@
|
||||||
/* (De)constructors */
|
/* (De)constructors */
|
||||||
|
|
||||||
list_t *list_alloc(list_action_t delete) {
|
list_t *list_alloc(list_action_t delete) {
|
||||||
list_t *list;
|
list_t *list = xmalloc_and_zero(sizeof(list_t));
|
||||||
|
|
||||||
list = xmalloc_and_zero(sizeof(list_t));
|
|
||||||
list->delete = delete;
|
list->delete = delete;
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
@ -52,9 +50,7 @@ void list_free_node(list_t *list, list_node_t *node) {
|
||||||
/* Insertion and deletion */
|
/* Insertion and deletion */
|
||||||
|
|
||||||
list_node_t *list_insert_head(list_t *list, void *data) {
|
list_node_t *list_insert_head(list_t *list, void *data) {
|
||||||
list_node_t *node;
|
list_node_t *node = list_alloc_node();
|
||||||
|
|
||||||
node = list_alloc_node();
|
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
node->prev = NULL;
|
node->prev = NULL;
|
||||||
|
@ -72,9 +68,7 @@ list_node_t *list_insert_head(list_t *list, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
list_node_t *list_insert_tail(list_t *list, void *data) {
|
list_node_t *list_insert_tail(list_t *list, void *data) {
|
||||||
list_node_t *node;
|
list_node_t *node = list_alloc_node();
|
||||||
|
|
||||||
node = list_alloc_node();
|
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
node->next = NULL;
|
node->next = NULL;
|
||||||
|
@ -92,9 +86,7 @@ list_node_t *list_insert_tail(list_t *list, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
list_node_t *list_insert_after(list_t *list, list_node_t *after, void *data) {
|
list_node_t *list_insert_after(list_t *list, list_node_t *after, void *data) {
|
||||||
list_node_t *node;
|
list_node_t *node = list_alloc_node();
|
||||||
|
|
||||||
node = list_alloc_node();
|
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
node->next = after->next;
|
node->next = after->next;
|
||||||
|
@ -177,12 +169,8 @@ void *list_get_tail(list_t *list) {
|
||||||
/* Fast list deletion */
|
/* Fast list deletion */
|
||||||
|
|
||||||
void list_delete_list(list_t *list) {
|
void list_delete_list(list_t *list) {
|
||||||
list_node_t *node, *next;
|
for(list_node_t *node = list->head, *next; next = node->next, node; node = next)
|
||||||
|
|
||||||
for(node = list->head; node; node = next) {
|
|
||||||
next = node->next;
|
|
||||||
list_free_node(list, node);
|
list_free_node(list, node);
|
||||||
}
|
|
||||||
|
|
||||||
list_free(list);
|
list_free(list);
|
||||||
}
|
}
|
||||||
|
@ -190,20 +178,12 @@ void list_delete_list(list_t *list) {
|
||||||
/* Traversing */
|
/* Traversing */
|
||||||
|
|
||||||
void list_foreach_node(list_t *list, list_action_node_t action) {
|
void list_foreach_node(list_t *list, list_action_node_t action) {
|
||||||
list_node_t *node, *next;
|
for(list_node_t *node = list->head, *next; next = node->next, node; node = next)
|
||||||
|
|
||||||
for(node = list->head; node; node = next) {
|
|
||||||
next = node->next;
|
|
||||||
action(node);
|
action(node);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_foreach(list_t *list, list_action_t action) {
|
void list_foreach(list_t *list, list_action_t action) {
|
||||||
list_node_t *node, *next;
|
for(list_node_t *node = list->head, *next; next = node->next, node; node = next)
|
||||||
|
|
||||||
for(node = list->head; node; node = next) {
|
|
||||||
next = node->next;
|
|
||||||
if(node->data)
|
if(node->data)
|
||||||
action(node->data);
|
action(node->data);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,4 +77,6 @@ extern void list_delete_list(list_t *);
|
||||||
extern void list_foreach(list_t *, list_action_t);
|
extern void list_foreach(list_t *, list_action_t);
|
||||||
extern void list_foreach_node(list_t *, list_action_node_t);
|
extern void list_foreach_node(list_t *, list_action_node_t);
|
||||||
|
|
||||||
|
#define list_each(type, item, list) (type *item = (type *)1; item; item = NULL) for(list_node_t *node = (list)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
|
||||||
|
|
||||||
#endif /* __TINC_LIST_H__ */
|
#endif /* __TINC_LIST_H__ */
|
||||||
|
|
|
@ -140,9 +140,7 @@ void logger(int level, int priority, const char *format, ...) {
|
||||||
if(logcontrol) {
|
if(logcontrol) {
|
||||||
suppress = true;
|
suppress = true;
|
||||||
logcontrol = false;
|
logcontrol = false;
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
if(!c->status.log)
|
if(!c->status.log)
|
||||||
continue;
|
continue;
|
||||||
logcontrol = true;
|
logcontrol = true;
|
||||||
|
|
|
@ -76,13 +76,9 @@ bool send_meta(connection_t *c, const char *buffer, int length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list)
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
|
|
||||||
if(c != from && c->status.active)
|
if(c != from && c->status.active)
|
||||||
send_meta(c, buffer, length);
|
send_meta(c, buffer, length);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
|
bool receive_meta_sptps(void *handle, uint8_t type, const char *data, uint16_t length) {
|
||||||
|
|
64
src/net.c
64
src/net.c
|
@ -44,33 +44,21 @@ time_t last_config_check = 0;
|
||||||
/* Purge edges and subnets of unreachable nodes. Use carefully. */
|
/* Purge edges and subnets of unreachable nodes. Use carefully. */
|
||||||
|
|
||||||
void purge(void) {
|
void purge(void) {
|
||||||
splay_node_t *nnode, *nnext, *enode, *enext, *snode, *snext;
|
|
||||||
node_t *n;
|
|
||||||
edge_t *e;
|
|
||||||
subnet_t *s;
|
|
||||||
|
|
||||||
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Purging unreachable nodes");
|
logger(DEBUG_PROTOCOL, LOG_DEBUG, "Purging unreachable nodes");
|
||||||
|
|
||||||
/* Remove all edges and subnets owned by unreachable nodes. */
|
/* Remove all edges and subnets owned by unreachable nodes. */
|
||||||
|
|
||||||
for(nnode = node_tree->head; nnode; nnode = nnext) {
|
for splay_each(node_t, n, node_tree) {
|
||||||
nnext = nnode->next;
|
|
||||||
n = nnode->data;
|
|
||||||
|
|
||||||
if(!n->status.reachable) {
|
if(!n->status.reachable) {
|
||||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Purging node %s (%s)", n->name, n->hostname);
|
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Purging node %s (%s)", n->name, n->hostname);
|
||||||
|
|
||||||
for(snode = n->subnet_tree->head; snode; snode = snext) {
|
for splay_each(subnet_t, s, n->subnet_tree) {
|
||||||
snext = snode->next;
|
|
||||||
s = snode->data;
|
|
||||||
send_del_subnet(everyone, s);
|
send_del_subnet(everyone, s);
|
||||||
if(!strictsubnets)
|
if(!strictsubnets)
|
||||||
subnet_del(n, s);
|
subnet_del(n, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(enode = n->edge_tree->head; enode; enode = enext) {
|
for splay_each(edge_t, e, n->edge_tree) {
|
||||||
enext = enode->next;
|
|
||||||
e = enode->data;
|
|
||||||
if(!tunnelserver)
|
if(!tunnelserver)
|
||||||
send_del_edge(everyone, e);
|
send_del_edge(everyone, e);
|
||||||
edge_del(e);
|
edge_del(e);
|
||||||
|
@ -80,20 +68,13 @@ void purge(void) {
|
||||||
|
|
||||||
/* Check if anyone else claims to have an edge to an unreachable node. If not, delete node. */
|
/* Check if anyone else claims to have an edge to an unreachable node. If not, delete node. */
|
||||||
|
|
||||||
for(nnode = node_tree->head; nnode; nnode = nnext) {
|
for splay_each(node_t, n, node_tree) {
|
||||||
nnext = nnode->next;
|
|
||||||
n = nnode->data;
|
|
||||||
|
|
||||||
if(!n->status.reachable) {
|
if(!n->status.reachable) {
|
||||||
for(enode = edge_weight_tree->head; enode; enode = enext) {
|
for splay_each(edge_t, e, edge_weight_tree)
|
||||||
enext = enode->next;
|
|
||||||
e = enode->data;
|
|
||||||
|
|
||||||
if(e->to == n)
|
if(e->to == n)
|
||||||
break;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if(!enode && (!strictsubnets || !n->subnet_tree->head))
|
if(!strictsubnets || !n->subnet_tree->head)
|
||||||
/* in strictsubnets mode do not delete nodes with subnets */
|
/* in strictsubnets mode do not delete nodes with subnets */
|
||||||
node_del(n);
|
node_del(n);
|
||||||
}
|
}
|
||||||
|
@ -159,10 +140,7 @@ void terminate_connection(connection_t *c, bool report) {
|
||||||
static void timeout_handler(int fd, short events, void *event) {
|
static void timeout_handler(int fd, short events, void *event) {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
|
|
||||||
if(c->status.control)
|
if(c->status.control)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -272,16 +250,12 @@ int reload_configuration(void) {
|
||||||
/* If StrictSubnet is set, expire deleted Subnets and read new ones in */
|
/* If StrictSubnet is set, expire deleted Subnets and read new ones in */
|
||||||
|
|
||||||
if(strictsubnets) {
|
if(strictsubnets) {
|
||||||
for(splay_node_t *node = subnet_tree->head; node; node = node->next) {
|
for splay_each(subnet_t, subnet, subnet_tree)
|
||||||
subnet_t *subnet = node->data;
|
|
||||||
subnet->expires = 1;
|
subnet->expires = 1;
|
||||||
}
|
|
||||||
|
|
||||||
load_all_subnets();
|
load_all_subnets();
|
||||||
|
|
||||||
for(splay_node_t *node = subnet_tree->head, *next; node; node = next) {
|
for splay_each(subnet_t, subnet, subnet_tree) {
|
||||||
next = node->next;
|
|
||||||
subnet_t *subnet = node->data;
|
|
||||||
if(subnet->expires == 1) {
|
if(subnet->expires == 1) {
|
||||||
send_del_subnet(everyone, subnet);
|
send_del_subnet(everyone, subnet);
|
||||||
if(subnet->owner->status.reachable)
|
if(subnet->owner->status.reachable)
|
||||||
|
@ -296,11 +270,9 @@ int reload_configuration(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { /* Only read our own subnets back in */
|
} else { /* Only read our own subnets back in */
|
||||||
for(splay_node_t *node = myself->subnet_tree->head; node; node = node->next) {
|
for splay_each(subnet_t, subnet, myself->subnet_tree)
|
||||||
subnet_t *subnet = node->data;
|
|
||||||
if(!subnet->expires)
|
if(!subnet->expires)
|
||||||
subnet->expires = 1;
|
subnet->expires = 1;
|
||||||
}
|
|
||||||
|
|
||||||
config_t *cfg = lookup_config(config_tree, "Subnet");
|
config_t *cfg = lookup_config(config_tree, "Subnet");
|
||||||
|
|
||||||
|
@ -324,9 +296,7 @@ int reload_configuration(void) {
|
||||||
cfg = lookup_config_next(config_tree, cfg);
|
cfg = lookup_config_next(config_tree, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(splay_node_t *node = myself->subnet_tree->head, *next; node; node = next) {
|
for splay_each(subnet_t, subnet, myself->subnet_tree) {
|
||||||
next = node->next;
|
|
||||||
subnet_t *subnet = node->data;
|
|
||||||
if(subnet->expires == 1) {
|
if(subnet->expires == 1) {
|
||||||
send_del_subnet(everyone, subnet);
|
send_del_subnet(everyone, subnet);
|
||||||
subnet_update(myself, subnet, false);
|
subnet_update(myself, subnet, false);
|
||||||
|
@ -341,10 +311,7 @@ int reload_configuration(void) {
|
||||||
|
|
||||||
/* Close connections to hosts that have a changed or deleted host config file */
|
/* Close connections to hosts that have a changed or deleted host config file */
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
connection_t *c = node->data;
|
|
||||||
next = node->next;
|
|
||||||
|
|
||||||
if(c->status.control)
|
if(c->status.control)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -363,10 +330,7 @@ int reload_configuration(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void retry(void) {
|
void retry(void) {
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
|
|
||||||
if(c->outgoing && !c->node) {
|
if(c->outgoing && !c->node) {
|
||||||
if(timeout_initialized(&c->outgoing->ev))
|
if(timeout_initialized(&c->outgoing->ev))
|
||||||
event_del(&c->outgoing->ev);
|
event_del(&c->outgoing->ev);
|
||||||
|
|
|
@ -79,8 +79,6 @@ bool localdiscovery = false;
|
||||||
|
|
||||||
static void send_mtu_probe_handler(int fd, short events, void *data) {
|
static void send_mtu_probe_handler(int fd, short events, void *data) {
|
||||||
node_t *n = data;
|
node_t *n = data;
|
||||||
vpn_packet_t packet;
|
|
||||||
int len, i;
|
|
||||||
int timeout = 1;
|
int timeout = 1;
|
||||||
|
|
||||||
n->mtuprobes++;
|
n->mtuprobes++;
|
||||||
|
@ -126,7 +124,9 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
||||||
timeout = pingtimeout;
|
timeout = pingtimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < 3 + localdiscovery; i++) {
|
for(int i = 0; i < 3 + localdiscovery; i++) {
|
||||||
|
int len;
|
||||||
|
|
||||||
if(n->maxmtu <= n->minmtu)
|
if(n->maxmtu <= n->minmtu)
|
||||||
len = n->maxmtu;
|
len = n->maxmtu;
|
||||||
else
|
else
|
||||||
|
@ -135,6 +135,7 @@ static void send_mtu_probe_handler(int fd, short events, void *data) {
|
||||||
if(len < 64)
|
if(len < 64)
|
||||||
len = 64;
|
len = 64;
|
||||||
|
|
||||||
|
vpn_packet_t packet;
|
||||||
memset(packet.data, 0, 14);
|
memset(packet.data, 0, 14);
|
||||||
randomize(packet.data + 14, len - 14);
|
randomize(packet.data + 14, len - 14);
|
||||||
packet.len = len;
|
packet.len = len;
|
||||||
|
@ -766,13 +767,9 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
||||||
// This guarantees all nodes receive the broadcast packet, and
|
// This guarantees all nodes receive the broadcast packet, and
|
||||||
// usually distributes the sending of broadcast packets over all nodes.
|
// usually distributes the sending of broadcast packets over all nodes.
|
||||||
case BMODE_MST:
|
case BMODE_MST:
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list)
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
|
|
||||||
if(c->status.active && c->status.mst && c != from->nexthop->connection)
|
if(c->status.active && c->status.mst && c != from->nexthop->connection)
|
||||||
send_packet(c->node, packet);
|
send_packet(c->node, packet);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// In direct mode, we send copies to each node we know of.
|
// In direct mode, we send copies to each node we know of.
|
||||||
|
@ -782,12 +779,9 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
||||||
if(from != myself)
|
if(from != myself)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for(splay_node_t *node = node_tree->head; node; node = node->next) {
|
for splay_each(node_t, n, node_tree)
|
||||||
node_t *n = node->data;
|
|
||||||
|
|
||||||
if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
|
if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
|
||||||
send_packet(n, packet);
|
send_packet(n, packet);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -803,9 +797,7 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
||||||
static time_t last_hard_try = 0;
|
static time_t last_hard_try = 0;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
for splay_each(edge_t, e, edge_weight_tree) {
|
||||||
e = node->data;
|
|
||||||
|
|
||||||
if(!e->to->status.reachable || e->to == myself)
|
if(!e->to->status.reachable || e->to == myself)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -294,11 +294,6 @@ void load_all_subnets(void) {
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
char *dname;
|
char *dname;
|
||||||
char *fname;
|
|
||||||
splay_tree_t *config_tree;
|
|
||||||
config_t *cfg;
|
|
||||||
subnet_t *s, *s2;
|
|
||||||
node_t *n;
|
|
||||||
|
|
||||||
xasprintf(&dname, "%s" SLASH "hosts", confbase);
|
xasprintf(&dname, "%s" SLASH "hosts", confbase);
|
||||||
dir = opendir(dname);
|
dir = opendir(dname);
|
||||||
|
@ -312,13 +307,16 @@ void load_all_subnets(void) {
|
||||||
if(!check_id(ent->d_name))
|
if(!check_id(ent->d_name))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
n = lookup_node(ent->d_name);
|
node_t *n = lookup_node(ent->d_name);
|
||||||
#ifdef _DIRENT_HAVE_D_TYPE
|
#ifdef _DIRENT_HAVE_D_TYPE
|
||||||
//if(ent->d_type != DT_REG)
|
//if(ent->d_type != DT_REG)
|
||||||
// continue;
|
// continue;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char *fname;
|
||||||
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
xasprintf(&fname, "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
||||||
|
|
||||||
|
splay_tree_t *config_tree;
|
||||||
init_configuration(&config_tree);
|
init_configuration(&config_tree);
|
||||||
read_config_options(config_tree, ent->d_name);
|
read_config_options(config_tree, ent->d_name);
|
||||||
read_config_file(config_tree, fname);
|
read_config_file(config_tree, fname);
|
||||||
|
@ -330,7 +328,9 @@ void load_all_subnets(void) {
|
||||||
node_add(n);
|
node_add(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||||
|
subnet_t *s, *s2;
|
||||||
|
|
||||||
if(!get_config_subnet(cfg, &s))
|
if(!get_config_subnet(cfg, &s))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -577,15 +577,9 @@ bool setup_myself_reloadable(void) {
|
||||||
Configure node_t myself and set up the local sockets (listen only)
|
Configure node_t myself and set up the local sockets (listen only)
|
||||||
*/
|
*/
|
||||||
static bool setup_myself(void) {
|
static bool setup_myself(void) {
|
||||||
config_t *cfg;
|
|
||||||
subnet_t *subnet;
|
|
||||||
char *name, *hostname, *cipher, *digest, *type;
|
char *name, *hostname, *cipher, *digest, *type;
|
||||||
char *fname = NULL;
|
char *fname = NULL;
|
||||||
char *address = NULL;
|
char *address = NULL;
|
||||||
char *envp[5];
|
|
||||||
struct addrinfo *ai, *aip, hint = {0};
|
|
||||||
int i, err;
|
|
||||||
int replaywin_int;
|
|
||||||
|
|
||||||
if(!(name = get_name())) {
|
if(!(name = get_name())) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Name for tinc daemon required!");
|
logger(DEBUG_ALWAYS, LOG_ERR, "Name for tinc daemon required!");
|
||||||
|
@ -633,15 +627,13 @@ static bool setup_myself(void) {
|
||||||
|
|
||||||
/* Read in all the subnets specified in the host configuration file */
|
/* Read in all the subnets specified in the host configuration file */
|
||||||
|
|
||||||
cfg = lookup_config(config_tree, "Subnet");
|
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||||
|
subnet_t *subnet;
|
||||||
|
|
||||||
while(cfg) {
|
|
||||||
if(!get_config_subnet(cfg, &subnet))
|
if(!get_config_subnet(cfg, &subnet))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
subnet_add(myself, subnet);
|
subnet_add(myself, subnet);
|
||||||
|
|
||||||
cfg = lookup_config_next(config_tree, cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check some options */
|
/* Check some options */
|
||||||
|
@ -669,6 +661,7 @@ static bool setup_myself(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int replaywin_int;
|
||||||
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
|
if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) {
|
||||||
if(replaywin_int < 0) {
|
if(replaywin_int < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "ReplayWindow cannot be negative!");
|
logger(DEBUG_ALWAYS, LOG_ERR, "ReplayWindow cannot be negative!");
|
||||||
|
@ -768,6 +761,7 @@ static bool setup_myself(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run tinc-up script to further initialize the tap interface */
|
/* Run tinc-up script to further initialize the tap interface */
|
||||||
|
char *envp[5];
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||||
|
@ -776,7 +770,7 @@ static bool setup_myself(void) {
|
||||||
|
|
||||||
execute_script("tinc-up", envp);
|
execute_script("tinc-up", envp);
|
||||||
|
|
||||||
for(i = 0; i < 4; i++)
|
for(int i = 0; i < 4; i++)
|
||||||
free(envp[i]);
|
free(envp[i]);
|
||||||
|
|
||||||
/* Run subnet-up scripts for our own subnets */
|
/* Run subnet-up scripts for our own subnets */
|
||||||
|
@ -799,7 +793,7 @@ static bool setup_myself(void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < listen_sockets; i++) {
|
for(int i = 0; i < listen_sockets; i++) {
|
||||||
salen = sizeof sa;
|
salen = sizeof sa;
|
||||||
if(getsockname(i + 3, &sa.sa, &salen) < 0) {
|
if(getsockname(i + 3, &sa.sa, &salen) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
|
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno));
|
||||||
|
@ -838,7 +832,7 @@ static bool setup_myself(void) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
listen_sockets = 0;
|
listen_sockets = 0;
|
||||||
cfg = lookup_config(config_tree, "BindToAddress");
|
config_t *cfg = lookup_config(config_tree, "BindToAddress");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
get_config_string(cfg, &address);
|
get_config_string(cfg, &address);
|
||||||
|
@ -858,12 +852,13 @@ static bool setup_myself(void) {
|
||||||
*address = 0;
|
*address = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct addrinfo *ai, hint = {0};
|
||||||
hint.ai_family = addressfamily;
|
hint.ai_family = addressfamily;
|
||||||
hint.ai_socktype = SOCK_STREAM;
|
hint.ai_socktype = SOCK_STREAM;
|
||||||
hint.ai_protocol = IPPROTO_TCP;
|
hint.ai_protocol = IPPROTO_TCP;
|
||||||
hint.ai_flags = AI_PASSIVE;
|
hint.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
|
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
|
||||||
free(address);
|
free(address);
|
||||||
|
|
||||||
if(err || !ai) {
|
if(err || !ai) {
|
||||||
|
@ -872,7 +867,7 @@ static bool setup_myself(void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(aip = ai; aip; aip = aip->ai_next) {
|
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
||||||
if(listen_sockets >= MAXSOCKETS) {
|
if(listen_sockets >= MAXSOCKETS) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
|
logger(DEBUG_ALWAYS, LOG_ERR, "Too many listening sockets");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -577,24 +577,19 @@ static void free_outgoing(outgoing_t *outgoing) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_outgoing_connections(void) {
|
void try_outgoing_connections(void) {
|
||||||
static config_t *cfg = NULL;
|
|
||||||
char *name;
|
|
||||||
outgoing_t *outgoing;
|
|
||||||
|
|
||||||
/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
|
/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
|
||||||
|
|
||||||
if(!outgoing_list) {
|
if(!outgoing_list) {
|
||||||
outgoing_list = list_alloc((list_action_t)free_outgoing);
|
outgoing_list = list_alloc((list_action_t)free_outgoing);
|
||||||
} else {
|
} else {
|
||||||
for(list_node_t *i = outgoing_list->head; i; i = i->next) {
|
for list_each(outgoing_t, outgoing, outgoing_list)
|
||||||
outgoing = i->data;
|
|
||||||
outgoing->timeout = -1;
|
outgoing->timeout = -1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure there is one outgoing_t in the list for each ConnectTo. */
|
/* Make sure there is one outgoing_t in the list for each ConnectTo. */
|
||||||
|
|
||||||
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
for(config_t *cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||||
|
char *name;
|
||||||
get_config_string(cfg, &name);
|
get_config_string(cfg, &name);
|
||||||
|
|
||||||
if(!check_id(name)) {
|
if(!check_id(name)) {
|
||||||
|
@ -607,8 +602,7 @@ void try_outgoing_connections(void) {
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
for(list_node_t *i = outgoing_list->head; i; i = i->next) {
|
for list_each(outgoing_t, outgoing, outgoing_list) {
|
||||||
outgoing = i->data;
|
|
||||||
if(!strcmp(outgoing->name, name)) {
|
if(!strcmp(outgoing->name, name)) {
|
||||||
found = true;
|
found = true;
|
||||||
outgoing->timeout = 0;
|
outgoing->timeout = 0;
|
||||||
|
@ -617,7 +611,7 @@ void try_outgoing_connections(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found) {
|
if(!found) {
|
||||||
outgoing = xmalloc_and_zero(sizeof *outgoing);
|
outgoing_t *outgoing = xmalloc_and_zero(sizeof *outgoing);
|
||||||
outgoing->name = name;
|
outgoing->name = name;
|
||||||
list_insert_tail(outgoing_list, outgoing);
|
list_insert_tail(outgoing_list, outgoing);
|
||||||
setup_outgoing_connection(outgoing);
|
setup_outgoing_connection(outgoing);
|
||||||
|
@ -626,9 +620,7 @@ void try_outgoing_connections(void) {
|
||||||
|
|
||||||
/* Terminate any connections whose outgoing_t is to be deleted. */
|
/* Terminate any connections whose outgoing_t is to be deleted. */
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list) {
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
if(c->outgoing && c->outgoing->timeout == -1) {
|
if(c->outgoing && c->outgoing->timeout == -1) {
|
||||||
c->outgoing = NULL;
|
c->outgoing = NULL;
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name);
|
logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name);
|
||||||
|
@ -638,10 +630,7 @@ void try_outgoing_connections(void) {
|
||||||
|
|
||||||
/* Delete outgoing_ts for which there is no ConnectTo. */
|
/* Delete outgoing_ts for which there is no ConnectTo. */
|
||||||
|
|
||||||
for(list_node_t *node = outgoing_list->head, *next; node; node = next) {
|
for list_each(outgoing_t, outgoing, outgoing_list)
|
||||||
next = node->next;
|
|
||||||
outgoing = node->data;
|
|
||||||
if(outgoing->timeout == -1)
|
if(outgoing->timeout == -1)
|
||||||
list_delete_node(outgoing_list, node);
|
list_delete_node(outgoing_list, node);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
28
src/node.c
28
src/node.c
|
@ -98,21 +98,11 @@ void node_add(node_t *n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void node_del(node_t *n) {
|
void node_del(node_t *n) {
|
||||||
splay_node_t *node, *next;
|
for splay_each(subnet_t, s, n->subnet_tree)
|
||||||
edge_t *e;
|
|
||||||
subnet_t *s;
|
|
||||||
|
|
||||||
for(node = n->subnet_tree->head; node; node = next) {
|
|
||||||
next = node->next;
|
|
||||||
s = node->data;
|
|
||||||
subnet_del(n, s);
|
subnet_del(n, s);
|
||||||
}
|
|
||||||
|
|
||||||
for(node = n->edge_tree->head; node; node = next) {
|
for splay_each(edge_t, e, n->edge_tree)
|
||||||
next = node->next;
|
|
||||||
e = node->data;
|
|
||||||
edge_del(e);
|
edge_del(e);
|
||||||
}
|
|
||||||
|
|
||||||
splay_delete(node_tree, n);
|
splay_delete(node_tree, n);
|
||||||
}
|
}
|
||||||
|
@ -147,30 +137,20 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_nodes(connection_t *c) {
|
bool dump_nodes(connection_t *c) {
|
||||||
splay_node_t *node;
|
for splay_each(node_t, n, node_tree)
|
||||||
node_t *n;
|
|
||||||
|
|
||||||
for(node = node_tree->head; node; node = node->next) {
|
|
||||||
n = node->data;
|
|
||||||
send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
|
send_request(c, "%d %d %s %s %d %d %d %d %x %x %s %s %d %hd %hd %hd %ld", CONTROL, REQ_DUMP_NODES,
|
||||||
n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(&n->outcipher),
|
n->name, n->hostname ?: "unknown port unknown", cipher_get_nid(&n->outcipher),
|
||||||
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression,
|
digest_get_nid(&n->outdigest), (int)digest_length(&n->outdigest), n->outcompression,
|
||||||
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
|
n->options, bitfield_to_int(&n->status, sizeof n->status), n->nexthop ? n->nexthop->name : "-",
|
||||||
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
|
n->via ? n->via->name ?: "-" : "-", n->distance, n->mtu, n->minmtu, n->maxmtu, (long)n->last_state_change);
|
||||||
}
|
|
||||||
|
|
||||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
|
return send_request(c, "%d %d", CONTROL, REQ_DUMP_NODES);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_traffic(connection_t *c) {
|
bool dump_traffic(connection_t *c) {
|
||||||
splay_node_t *node;
|
for splay_each(node_t, n, node_tree)
|
||||||
node_t *n;
|
|
||||||
|
|
||||||
for(node = node_tree->head; node; node = node->next) {
|
|
||||||
n = node->data;
|
|
||||||
send_request(c, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_TRAFFIC,
|
send_request(c, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, CONTROL, REQ_DUMP_TRAFFIC,
|
||||||
n->name, n->in_packets, n->in_bytes, n->out_packets, n->out_bytes);
|
n->name, n->in_packets, n->in_bytes, n->out_packets, n->out_bytes);
|
||||||
}
|
|
||||||
|
|
||||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
|
return send_request(c, "%d %d", CONTROL, REQ_DUMP_TRAFFIC);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,6 @@ static SERVICE_STATUS_HANDLE statushandle = 0;
|
||||||
|
|
||||||
static bool install_service(void) {
|
static bool install_service(void) {
|
||||||
char command[4096] = "\"";
|
char command[4096] = "\"";
|
||||||
char **argp;
|
|
||||||
bool space;
|
|
||||||
SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
|
SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
|
||||||
|
|
||||||
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||||
|
@ -74,8 +72,8 @@ static bool install_service(void) {
|
||||||
|
|
||||||
strncat(command, "\"", sizeof command - strlen(command));
|
strncat(command, "\"", sizeof command - strlen(command));
|
||||||
|
|
||||||
for(argp = g_argv + 1; *argp; argp++) {
|
for(char **argp = g_argv + 1; *argp; argp++) {
|
||||||
space = strchr(*argp, ' ');
|
char &space = strchr(*argp, ' ');
|
||||||
strncat(command, " ", sizeof command - strlen(command));
|
strncat(command, " ", sizeof command - strlen(command));
|
||||||
|
|
||||||
if(space)
|
if(space)
|
||||||
|
|
|
@ -186,15 +186,10 @@ bool seen_request(const char *request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void age_past_requests(int fd, short events, void *data) {
|
static void age_past_requests(int fd, short events, void *data) {
|
||||||
splay_node_t *node, *next;
|
|
||||||
past_request_t *p;
|
|
||||||
int left = 0, deleted = 0;
|
int left = 0, deleted = 0;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
for(node = past_request_tree->head; node; node = next) {
|
for splay_each(past_request_t, p, past_request_tree) {
|
||||||
next = node->next;
|
|
||||||
p = node->data;
|
|
||||||
|
|
||||||
if(p->firstseen + pinginterval <= now)
|
if(p->firstseen + pinginterval <= now)
|
||||||
splay_delete_node(past_request_tree, node), deleted++;
|
splay_delete_node(past_request_tree, node), deleted++;
|
||||||
else
|
else
|
||||||
|
|
|
@ -508,34 +508,21 @@ bool send_ack(connection_t *c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_everything(connection_t *c) {
|
static void send_everything(connection_t *c) {
|
||||||
splay_node_t *node, *node2;
|
|
||||||
node_t *n;
|
|
||||||
subnet_t *s;
|
|
||||||
edge_t *e;
|
|
||||||
|
|
||||||
/* Send all known subnets and edges */
|
/* Send all known subnets and edges */
|
||||||
|
|
||||||
if(tunnelserver) {
|
if(tunnelserver) {
|
||||||
for(node = myself->subnet_tree->head; node; node = node->next) {
|
for splay_each(subnet_t, s, myself->subnet_tree)
|
||||||
s = node->data;
|
|
||||||
send_add_subnet(c, s);
|
send_add_subnet(c, s);
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(node = node_tree->head; node; node = node->next) {
|
for splay_each(node_t, n, node_tree) {
|
||||||
n = node->data;
|
for splay_each(subnet_t, s, n->subnet_tree)
|
||||||
|
|
||||||
for(node2 = n->subnet_tree->head; node2; node2 = node2->next) {
|
|
||||||
s = node2->data;
|
|
||||||
send_add_subnet(c, s);
|
send_add_subnet(c, s);
|
||||||
}
|
|
||||||
|
|
||||||
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
for splay_each(edge_t, e, n->edge_tree)
|
||||||
e = node2->data;
|
|
||||||
send_add_edge(c, e);
|
send_add_edge(c, e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,23 +40,16 @@ void send_key_changed(void) {
|
||||||
|
|
||||||
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
|
/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list)
|
||||||
next = node->next;
|
if(c->status.active && c->node && c->node->status.reachable && !c->node->status.sptps)
|
||||||
connection_t *c = node->data;
|
send_ans_key(c->node);
|
||||||
if(c->status.active && c->node && c->node->status.reachable) {
|
|
||||||
if(!c->node->status.sptps)
|
|
||||||
send_ans_key(c->node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Force key exchange for connections using SPTPS */
|
/* Force key exchange for connections using SPTPS */
|
||||||
|
|
||||||
if(experimental) {
|
if(experimental) {
|
||||||
for(splay_node_t *node = node_tree->head; node; node = node->next) {
|
for splay_each(node_t, n, node_tree)
|
||||||
node_t *n = node->data;
|
|
||||||
if(n->status.reachable && n->status.validkey && n->status.sptps)
|
if(n->status.reachable && n->status.validkey && n->status.sptps)
|
||||||
sptps_force_kex(&n->sptps);
|
sptps_force_kex(&n->sptps);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
src/route.c
19
src/route.c
|
@ -189,9 +189,7 @@ static void age_subnets(int fd, short events, void *data) {
|
||||||
bool left = false;
|
bool left = false;
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
|
|
||||||
for(splay_node_t *node = myself->subnet_tree->head, *next; node; node = next) {
|
for splay_each(subnet_t, s, myself->subnet_tree) {
|
||||||
next = node->next;
|
|
||||||
subnet_t *s = node->data;
|
|
||||||
if(s->expires && s->expires < now) {
|
if(s->expires && s->expires < now) {
|
||||||
if(debug_level >= DEBUG_TRAFFIC) {
|
if(debug_level >= DEBUG_TRAFFIC) {
|
||||||
char netstr[MAXNETSTR];
|
char netstr[MAXNETSTR];
|
||||||
|
@ -199,12 +197,9 @@ static void age_subnets(int fd, short events, void *data) {
|
||||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Subnet %s expired", netstr);
|
logger(DEBUG_TRAFFIC, LOG_INFO, "Subnet %s expired", netstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list)
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
if(c->status.active)
|
if(c->status.active)
|
||||||
send_del_subnet(c, s);
|
send_del_subnet(c, s);
|
||||||
}
|
|
||||||
|
|
||||||
subnet_del(myself, s);
|
subnet_del(myself, s);
|
||||||
} else {
|
} else {
|
||||||
|
@ -237,12 +232,9 @@ static void learn_mac(mac_t *address) {
|
||||||
|
|
||||||
/* And tell all other tinc daemons it's our MAC */
|
/* And tell all other tinc daemons it's our MAC */
|
||||||
|
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
for list_each(connection_t, c, connection_list)
|
||||||
next = node->next;
|
|
||||||
connection_t *c = node->data;
|
|
||||||
if(c->status.active)
|
if(c->status.active)
|
||||||
send_add_subnet(c, subnet);
|
send_add_subnet(c, subnet);
|
||||||
}
|
|
||||||
|
|
||||||
if(!timeout_initialized(&age_subnets_event))
|
if(!timeout_initialized(&age_subnets_event))
|
||||||
timeout_set(&age_subnets_event, age_subnets, NULL);
|
timeout_set(&age_subnets_event, age_subnets, NULL);
|
||||||
|
@ -872,9 +864,8 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
||||||
|
|
||||||
static void send_pcap(vpn_packet_t *packet) {
|
static void send_pcap(vpn_packet_t *packet) {
|
||||||
pcap = false;
|
pcap = false;
|
||||||
for(list_node_t *node = connection_list->head, *next; node; node = next) {
|
|
||||||
next = node->next;
|
for list_each(connection_t, c, connection_list) {
|
||||||
connection_t *c = node->data;
|
|
||||||
if(!c->status.pcap)
|
if(!c->status.pcap)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -530,9 +530,7 @@ void splay_delete(splay_tree_t *tree, void *data) {
|
||||||
/* Fast tree cleanup */
|
/* Fast tree cleanup */
|
||||||
|
|
||||||
void splay_delete_tree(splay_tree_t *tree) {
|
void splay_delete_tree(splay_tree_t *tree) {
|
||||||
splay_node_t *node, *next;
|
for(splay_node_t *node = tree->head, *next; node; node = next) {
|
||||||
|
|
||||||
for(node = tree->head; node; node = next) {
|
|
||||||
next = node->next;
|
next = node->next;
|
||||||
splay_free_node(tree, node);
|
splay_free_node(tree, node);
|
||||||
}
|
}
|
||||||
|
@ -543,18 +541,14 @@ void splay_delete_tree(splay_tree_t *tree) {
|
||||||
/* Tree walking */
|
/* Tree walking */
|
||||||
|
|
||||||
void splay_foreach(const splay_tree_t *tree, splay_action_t action) {
|
void splay_foreach(const splay_tree_t *tree, splay_action_t action) {
|
||||||
splay_node_t *node, *next;
|
for(splay_node_t *node = tree->head, *next; node; node = next) {
|
||||||
|
|
||||||
for(node = tree->head; node; node = next) {
|
|
||||||
next = node->next;
|
next = node->next;
|
||||||
action(node->data);
|
action(node->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void splay_foreach_node(const splay_tree_t *tree, splay_action_t action) {
|
void splay_foreach_node(const splay_tree_t *tree, splay_action_t action) {
|
||||||
splay_node_t *node, *next;
|
for(splay_node_t *node = tree->head, *next; node; node = next) {
|
||||||
|
|
||||||
for(node = tree->head; node; node = next) {
|
|
||||||
next = node->next;
|
next = node->next;
|
||||||
action(node);
|
action(node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,4 +104,6 @@ extern splay_node_t *splay_search_closest_greater_node(splay_tree_t *, const voi
|
||||||
extern void splay_foreach(const splay_tree_t *, splay_action_t);
|
extern void splay_foreach(const splay_tree_t *, splay_action_t);
|
||||||
extern void splay_foreach_node(const splay_tree_t *, splay_action_t);
|
extern void splay_foreach_node(const splay_tree_t *, splay_action_t);
|
||||||
|
|
||||||
|
#define splay_each(type, item, tree) (type *item = (type *)1; item; item = NULL) for(splay_node_t *node = (tree)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
39
src/subnet.c
39
src/subnet.c
|
@ -110,8 +110,7 @@ subnet_t *lookup_subnet(const node_t *owner, const subnet_t *subnet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
|
subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
|
||||||
subnet_t *p, *r = NULL;
|
subnet_t *r = NULL;
|
||||||
splay_node_t *n;
|
|
||||||
|
|
||||||
// Check if this address is cached
|
// Check if this address is cached
|
||||||
|
|
||||||
|
@ -120,9 +119,7 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
|
||||||
|
|
||||||
// Search all subnets for a matching one
|
// Search all subnets for a matching one
|
||||||
|
|
||||||
for(n = owner ? owner->subnet_tree->head : subnet_tree->head; n; n = n->next) {
|
for splay_each(subnet_t, p, owner ? owner->subnet_tree : subnet_tree) {
|
||||||
p = n->data;
|
|
||||||
|
|
||||||
if(!p || p->type != SUBNET_MAC)
|
if(!p || p->type != SUBNET_MAC)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -142,8 +139,7 @@ subnet_t *lookup_subnet_mac(const node_t *owner, const mac_t *address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
|
subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
|
||||||
subnet_t *p, *r = NULL;
|
subnet_t *r = NULL;
|
||||||
splay_node_t *n;
|
|
||||||
|
|
||||||
// Check if this address is cached
|
// Check if this address is cached
|
||||||
|
|
||||||
|
@ -152,9 +148,7 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
|
||||||
|
|
||||||
// Search all subnets for a matching one
|
// Search all subnets for a matching one
|
||||||
|
|
||||||
for(n = subnet_tree->head; n; n = n->next) {
|
for splay_each(subnet_t, p, subnet_tree) {
|
||||||
p = n->data;
|
|
||||||
|
|
||||||
if(!p || p->type != SUBNET_IPV4)
|
if(!p || p->type != SUBNET_IPV4)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -174,8 +168,7 @@ subnet_t *lookup_subnet_ipv4(const ipv4_t *address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
|
subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
|
||||||
subnet_t *p, *r = NULL;
|
subnet_t *r = NULL;
|
||||||
splay_node_t *n;
|
|
||||||
|
|
||||||
// Check if this address is cached
|
// Check if this address is cached
|
||||||
|
|
||||||
|
@ -184,9 +177,7 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
|
||||||
|
|
||||||
// Search all subnets for a matching one
|
// Search all subnets for a matching one
|
||||||
|
|
||||||
for(n = subnet_tree->head; n; n = n->next) {
|
for splay_each(subnet_t, p, subnet_tree) {
|
||||||
p = n->data;
|
|
||||||
|
|
||||||
if(!p || p->type != SUBNET_IPV6)
|
if(!p || p->type != SUBNET_IPV6)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -206,15 +197,13 @@ subnet_t *lookup_subnet_ipv6(const ipv6_t *address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
||||||
splay_node_t *node;
|
|
||||||
int i;
|
|
||||||
char *envp[9] = {NULL};
|
|
||||||
char netstr[MAXNETSTR];
|
char netstr[MAXNETSTR];
|
||||||
char *name, *address, *port;
|
char *name, *address, *port;
|
||||||
char empty[] = "";
|
char empty[] = "";
|
||||||
|
|
||||||
// Prepare environment variables to be passed to the script
|
// Prepare environment variables to be passed to the script
|
||||||
|
|
||||||
|
char *envp[9] = {NULL};
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
||||||
|
@ -232,10 +221,10 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
||||||
name = up ? "subnet-up" : "subnet-down";
|
name = up ? "subnet-up" : "subnet-down";
|
||||||
|
|
||||||
if(!subnet) {
|
if(!subnet) {
|
||||||
for(node = owner->subnet_tree->head; node; node = node->next) {
|
for splay_each(subnet_t, subnet, owner->subnet_tree) {
|
||||||
subnet = node->data;
|
|
||||||
if(!net2str(netstr, sizeof netstr, subnet))
|
if(!net2str(netstr, sizeof netstr, subnet))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Strip the weight from the subnet, and put it in its own environment variable
|
// Strip the weight from the subnet, and put it in its own environment variable
|
||||||
char *weight = strchr(netstr, '#');
|
char *weight = strchr(netstr, '#');
|
||||||
if(weight)
|
if(weight)
|
||||||
|
@ -270,19 +259,17 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; envp[i] && i < 8; i++)
|
for(int i = 0; envp[i] && i < 8; i++)
|
||||||
free(envp[i]);
|
free(envp[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_subnets(connection_t *c) {
|
bool dump_subnets(connection_t *c) {
|
||||||
char netstr[MAXNETSTR];
|
for splay_each(subnet_t, subnet, subnet_tree) {
|
||||||
subnet_t *subnet;
|
char netstr[MAXNETSTR];
|
||||||
splay_node_t *node;
|
|
||||||
|
|
||||||
for(node = subnet_tree->head; node; node = node->next) {
|
|
||||||
subnet = node->data;
|
|
||||||
if(!net2str(netstr, sizeof netstr, subnet))
|
if(!net2str(netstr, sizeof netstr, subnet))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
send_request(c, "%d %d %s %s",
|
send_request(c, "%d %d %s %s",
|
||||||
CONTROL, REQ_DUMP_SUBNETS,
|
CONTROL, REQ_DUMP_SUBNETS,
|
||||||
netstr, subnet->owner->name);
|
netstr, subnet->owner->name);
|
||||||
|
|
|
@ -194,7 +194,7 @@ bool str2net(subnet_t *subnet, const char *subnetstr) {
|
||||||
subnet->net.ipv4.prefixlength = l;
|
subnet->net.ipv4.prefixlength = l;
|
||||||
subnet->weight = weight;
|
subnet->weight = weight;
|
||||||
|
|
||||||
for(i = 0; i < 4; i++) {
|
for(int i = 0; i < 4; i++) {
|
||||||
if(x[i] > 255)
|
if(x[i] > 255)
|
||||||
return false;
|
return false;
|
||||||
subnet->net.ipv4.address.x[i] = x[i];
|
subnet->net.ipv4.address.x[i] = x[i];
|
||||||
|
|
19
src/top.c
19
src/top.c
|
@ -84,10 +84,8 @@ static void update(int fd) {
|
||||||
uint64_t out_packets;
|
uint64_t out_packets;
|
||||||
uint64_t out_bytes;
|
uint64_t out_bytes;
|
||||||
|
|
||||||
for(list_node_t *i = node_list.head; i; i = i->next) {
|
for list_each(nodestats_t, ns, &node_list)
|
||||||
nodestats_t *node = i->data;
|
ns->known = false;
|
||||||
node->known = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(recvline(fd, line, sizeof line)) {
|
while(recvline(fd, line, sizeof line)) {
|
||||||
int n = sscanf(line, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, &code, &req, name, &in_packets, &in_bytes, &out_packets, &out_bytes);
|
int n = sscanf(line, "%d %d %s %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, &code, &req, name, &in_packets, &in_bytes, &out_packets, &out_bytes);
|
||||||
|
@ -103,18 +101,17 @@ static void update(int fd) {
|
||||||
|
|
||||||
nodestats_t *found = NULL;
|
nodestats_t *found = NULL;
|
||||||
|
|
||||||
for(list_node_t *i = node_list.head; i; i = i->next) {
|
for list_each(nodestats_t, ns, &node_list) {
|
||||||
nodestats_t *node = i->data;
|
int result = strcmp(name, ns->name);
|
||||||
int result = strcmp(name, node->name);
|
|
||||||
if(result > 0) {
|
if(result > 0) {
|
||||||
continue;
|
continue;
|
||||||
} if(result == 0) {
|
} if(result == 0) {
|
||||||
found = node;
|
found = ns;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
found = xmalloc_and_zero(sizeof *found);
|
found = xmalloc_and_zero(sizeof *found);
|
||||||
found->name = xstrdup(name);
|
found->name = xstrdup(name);
|
||||||
list_insert_before(&node_list, i, found);
|
list_insert_before(&node_list, node, found);
|
||||||
changed = true;
|
changed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -152,8 +149,8 @@ static void redraw(void) {
|
||||||
if(changed) {
|
if(changed) {
|
||||||
n = 0;
|
n = 0;
|
||||||
sorted = xrealloc(sorted, node_list.count * sizeof *sorted);
|
sorted = xrealloc(sorted, node_list.count * sizeof *sorted);
|
||||||
for(list_node_t *i = node_list.head; i; i = i->next)
|
for list_each(nodestats_t, ns, &node_list)
|
||||||
sorted[n++] = i->data;
|
sorted[n++] = ns;
|
||||||
changed = false;
|
changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,7 @@ int hex2bin(const char *src, char *dst, int length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int bin2hex(const char *src, char *dst, int length) {
|
int bin2hex(const char *src, char *dst, int length) {
|
||||||
int i;
|
for(int i = length - 1; i >= 0; i--) {
|
||||||
for(i = length - 1; i >= 0; i--) {
|
|
||||||
dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15];
|
dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15];
|
||||||
dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4];
|
dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue