Switch to K&R style indentation.
[tinc] / src / protocol_node.c
1 /*
2     protocol_node.c -- handle the meta-protocol, nodes
3     Copyright (C) 1999-2002 Ivo Timmermans <ivo@o2w.nl>,
4                   2000-2002 Guus Sliepen <guus@sliepen.eu.org>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: protocol_node.c,v 1.1.4.8 2002/09/09 21:25:02 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <syslog.h>
28 #include <stdio.h>
29 #include <stdarg.h>
30 #include <errno.h>
31
32 #include <utils.h>
33 #include <xalloc.h>
34 #include <avl_tree.h>
35
36 #include "conf.h"
37 #include "net.h"
38 #include "netutl.h"
39 #include "protocol.h"
40 #include "meta.h"
41 #include "connection.h"
42 #include "node.h"
43
44 #include "system.h"
45
46 int send_add_node(connection_t * c, node_t * n)
47 {
48         int x;
49         char *address, *port;
50         cp();
51         if(!n->status.reachable)
52                 return 0;
53
54         sockaddr2str(&n->address, &address, &port);
55         x = send_request(c, "%d %s %s %s %lx %d %s %s", ADD_NODE, n->name, address, port, n->options, n->distance + 1,  // Alternatively, use n->distance + c->estimated_weight
56                                          n->prevhop->name, n->via->name);
57         free(address);
58         free(port);
59         cp();
60         return x;
61 }
62
63 int add_node_h(connection_t * c)
64 {
65         connection_t *other;
66         node_t *n, *prevhop, *via;
67         char name[MAX_STRING_SIZE];
68         char address[MAX_STRING_SIZE];
69         char port[MAX_STRING_SIZE];
70         char prevhopname[MAX_STRING_SIZE];
71         char vianame[MAX_STRING_SIZE];
72         long int options;
73         int distance;
74         avl_node_t *node;
75         cp();
76         if(sscanf
77            (c->buffer,
78                 "%*d " MAX_STRING " " MAX_STRING " " MAX_STRING " %lx %d " MAX_STRING
79                 " " MAX_STRING, name, address, port, &options, &distance, prevhopname,
80                 vianame) != 7) {
81                 syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_NODE", c->name,
82                            c->hostname);
83                 return -1;
84         }
85
86         /* Check if names are valid */
87
88         if(check_id(name)) {
89                 syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_NODE", c->name,
90                            c->hostname, _("invalid name"));
91                 return -1;
92         }
93
94         /* This node is indirect if it's nexthop is as well */
95
96         if(c->node->options & OPTION_INDIRECT)
97                 options |= OPTION_INDIRECT;
98
99         /* Lookup nodes */
100
101         prevhop = lookup_node(prevhopname);
102
103         if(!prevhop) {
104                 prevhop = new_node();
105                 prevhop->name = xstrdup(prevhopname);
106                 node_add(prevhop);
107         }
108
109         via = lookup_node(vianame);
110
111         if(!via) {
112                 via = new_node();
113                 via->name = xstrdup(vianame);
114                 node_add(via);
115         }
116
117         n = lookup_node(name);
118
119         if(!n) {
120                 // It's a new node. Add it and tell the others.
121                 n = new_node();
122                 n->name = xstrdup(name);
123                 n->address = str2sockaddr(address, port);
124                 n->hostname = sockaddr2hostname(&n->address);
125                 n->options = options;
126                 n->distance = distance;
127                 n->nexthop = c->node;
128                 n->prevhop = prevhop;
129                 n->via = via;
130                 node_add(n);
131                 if(prevhop == myself) {
132                         syslog(LOG_WARNING,
133                                    _
134                                    ("Got ADD_NODE %s prevhop %s via %s from %s, sending back a DEL_NODE!"),
135                                    name, prevhopname, vianame, c->name);
136                         // send_del_node(c, n);
137                         return 0;
138                 }
139                 n->status.reachable = 1;
140         } else {
141                 // If this ADD_NODE is closer or more direct, use it instead of the old one.
142                 if(!n->status.reachable
143                    || ((n->options & OPTION_INDIRECT) && !(options & OPTION_INDIRECT))
144                    || n->distance > distance) {
145                         if(prevhop == myself) {
146                                 syslog(LOG_WARNING,
147                                            _("Got ADD_NODE %s prevhop %s via %s from %s!"), name,
148                                            prevhopname, vianame, c->name);
149                                 // send_del_node(c, n);
150                                 return 0;
151                         }
152                         node = avl_unlink(node_udp_tree, n);
153                         n->address = str2sockaddr(address, port);
154                         avl_insert_node(node_udp_tree, node);
155                         if(n->hostname)
156                                 free(n->hostname);
157                         n->hostname = sockaddr2hostname(&n->address);
158                         n->options = options;
159                         n->distance = distance;
160                         n->via = n->nexthop = c->node;
161                         n->status.reachable = 1;
162                         n->status.validkey = 0;
163                         n->status.waitingforkey = 0;
164                 } else
165                         // Otherwise, just ignore it.
166                         return 0;
167         }
168
169         /* Tell the rest about the new node */
170
171         for(node = connection_tree->head; node; node = node->next) {
172                 other = (connection_t *) node->data;
173                 if(other->status.active && other != c)
174                         send_add_node(other, n);
175         }
176
177         cp();
178         return 0;
179 }
180
181 int send_del_node(connection_t * c, node_t * n)
182 {
183         cp();
184         return send_request(c, "%d %s %s", DEL_NODE, n->name, n->prevhop->name);
185 }
186
187 int del_node_h(connection_t * c)
188 {
189         char name[MAX_STRING_SIZE];
190         char prevhopname[MAX_STRING_SIZE];
191         node_t *n, *prevhop;
192         connection_t *other;
193         avl_node_t *node;
194         cp();
195         if(sscanf(c->buffer, "%*d " MAX_STRING " " MAX_STRING, name, prevhopname) !=
196            2) {
197                 syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_NODE", c->name,
198                            c->hostname);
199                 return -1;
200         }
201
202         /* Check if names are valid */
203
204         if(check_id(name)) {
205                 syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_NODE", c->name,
206                            c->hostname, _("invalid name"));
207                 return -1;
208         }
209
210         /* Lookup nodes */
211
212         n = lookup_node(name);
213         prevhop = lookup_node(prevhopname);
214
215         if(!n || !prevhop) {
216                 if(debug_lvl >= DEBUG_PROTOCOL)
217                         syslog(LOG_WARNING,
218                                    _
219                                    ("Got %s from %s (%s) which does not appear in the node tree"),
220                                    "DEL_NODE", c->name, c->hostname);
221                 return 0;
222         }
223
224         /* If we got a DEL_NODE but we know of a different route to it, tell the one who send the DEL_NODE */
225
226         if(n->nexthop != c->node) {
227                 return send_add_node(c, n);
228         }
229
230         /* Otherwise, tell the rest about the deleted node */
231
232         for(node = connection_tree->head; node; node = node->next) {
233                 other = (connection_t *) node->data;
234                 if(other->status.active && other != c)
235                         send_del_node(other, n);
236         }
237
238         /* "Delete" the node */
239
240         n->status.reachable = 0;
241         n->status.validkey = 0;
242         cp();
243         return 0;
244 }