4fd5354bd70a0b478164b08eecccca1b73ae50f6
[tinc] / src / protocol_edge.c
1 /*
2     protocol_edge.c -- handle the meta-protocol, edges
3     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
4                   2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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_edge.c,v 1.1.4.3 2002/03/21 23:11:53 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 #include "edge.h"
44 #include "graph.h"
45
46 #include "system.h"
47
48 int send_add_edge(connection_t *c, edge_t *e)
49 {
50   int x;
51   char *from_tcpaddress, *from_tcpport, *from_udpaddress, *from_udpport;
52   char *to_tcpaddress, *to_tcpport, *to_udpaddress, *to_udpport;
53 cp
54   sockaddr2str(&e->from.tcpaddress, &from_tcpaddress, &from_tcpport);
55   sockaddr2str(&e->from.udpaddress, &from_udpaddress, &from_udpport);
56   sockaddr2str(&e->to.tcpaddress, &to_tcpaddress, &to_tcpport);
57   sockaddr2str(&e->to.udpaddress, &to_udpaddress, &to_udpport);
58   x = send_request(c, "%d %lx %s %s %s %s %s %s %s %s %lx %d", ADD_EDGE, random(),
59                       e->from.node->name, from_tcpaddress, from_tcpport, from_udpport,
60                       e->to.node->name, to_tcpaddress, to_tcpport, to_udpport,
61                       e->options, e->weight);
62   free(from_tcpaddress);
63   free(from_tcpport);
64   free(from_udpaddress);
65   free(from_udpport);
66   free(to_tcpaddress);
67   free(to_tcpport);
68   free(to_udpaddress);
69   free(to_udpport);
70 cp
71   return x;
72 }
73
74 int add_edge_h(connection_t *c)
75 {
76   connection_t *other;
77   edge_t *e;
78   node_t *from, *to;
79   char from_name[MAX_STRING_SIZE];
80   char to_name[MAX_STRING_SIZE];
81   char from_address[MAX_STRING_SIZE];
82   char from_tcpport[MAX_STRING_SIZE];
83   char from_udpport[MAX_STRING_SIZE];
84   char to_address[MAX_STRING_SIZE];
85   char to_tcpport[MAX_STRING_SIZE];
86   char to_udpport[MAX_STRING_SIZE];
87   sockaddr_t from_tcpaddress, from_udpaddress;
88   sockaddr_t to_tcpaddress, to_udpaddress;
89   long int options;
90   int weight;
91   avl_node_t *node;
92 cp
93   if(sscanf(c->buffer, "%*d %*lx "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
94             from_name, from_address, from_tcpport, from_udpport,
95             to_name, to_address, to_tcpport, to_udpport,
96             &options, &weight) != 10)
97     {
98        syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name, c->hostname);
99        return -1;
100     }
101
102   /* Check if names are valid */
103
104   if(check_id(from_name))
105     {
106       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name, c->hostname, _("invalid name"));
107       return -1;
108     }
109
110   if(check_id(to_name))
111     {
112       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_EDGE", c->name, c->hostname, _("invalid name"));
113       return -1;
114     }
115
116   if(seen_request(c->buffer))
117     return 0;
118
119   /* Lookup nodes */
120
121   from = lookup_node(from_name);
122   
123   if(!from)
124     {
125       from = new_node();
126       from->name = xstrdup(from_name);
127       node_add(from);
128     }
129
130   to = lookup_node(to_name);
131   
132   if(!to)
133     {
134       to = new_node();
135       to->name = xstrdup(to_name);
136       node_add(to);
137     }
138
139   /* Convert addresses */
140   
141   from_tcpaddress = str2sockaddr(from_address, from_tcpport);
142   from_udpaddress = str2sockaddr(from_address, from_udpport);
143   to_tcpaddress = str2sockaddr(to_address, to_tcpport);
144   to_udpaddress = str2sockaddr(to_address, to_udpport);
145
146   /* Check if edge already exists */
147   
148   e = lookup_edge(from, to);
149   
150   if(e)
151   {
152     if(e->weight != weight || e->options != options
153        || ((e->from.node == from) && (sockaddrcmp(&e->from.tcpaddress, &from_tcpaddress) || sockaddrcmp(&e->from.udpaddress, &from_udpaddress) || sockaddrcmp(&e->to.tcpaddress, &to_tcpaddress) || sockaddrcmp(&e->to.udpaddress, &to_udpaddress)))
154        || ((e->from.node == to) && (sockaddrcmp(&e->from.tcpaddress, &to_tcpaddress) || sockaddrcmp(&e->from.udpaddress, &to_udpaddress) || sockaddrcmp(&e->to.tcpaddress, &from_tcpaddress) || sockaddrcmp(&e->to.udpaddress, &from_udpaddress)))
155       )
156     {
157       if(from == myself || to == myself)
158       {
159         if(debug_lvl >= DEBUG_PROTOCOL)
160           syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"), "ADD_EDGE", c->name, c->hostname);
161         send_add_edge(c, e);
162         return 0;
163       }
164       else
165       {
166         if(debug_lvl >= DEBUG_PROTOCOL)
167           syslog(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"), "ADD_EDGE", c->name, c->hostname);
168         edge_del(e);
169       }
170     }
171     else
172       return 0;
173   }
174   else if(from == myself || to == myself)
175   {
176     if(debug_lvl >= DEBUG_PROTOCOL)
177       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"), "ADD_EDGE", c->name, c->hostname);
178     e = new_edge();
179     e->from.node = from;
180     e->to.node = to;
181     send_del_edge(c, e);
182     free_edge(e);
183     return 0;
184   }
185
186   e = new_edge();
187   e->from.node = from;
188   e->from.tcpaddress = from_tcpaddress;
189   e->from.udpaddress = from_udpaddress;
190   e->to.node = to;
191   e->to.tcpaddress = to_tcpaddress;
192   e->to.udpaddress = to_udpaddress;
193   e->options = options;
194   e->weight = weight;
195   edge_add(e);
196
197   /* Tell the rest about the new edge */
198
199   for(node = connection_tree->head; node; node = node->next)
200     {
201       other = (connection_t *)node->data;
202       if(other->status.active && other != c)
203         send_request(other, "%s", c->buffer);
204     }
205
206   /* Run MST before or after we tell the rest? */
207
208   graph();
209 cp
210   return 0;
211 }
212
213 int send_del_edge(connection_t *c, edge_t *e)
214 {
215 cp
216   return send_request(c, "%d %lx %s %s", DEL_EDGE, random(),
217                       e->from.node->name, e->to.node->name);
218 }
219
220 int del_edge_h(connection_t *c)
221 {
222   edge_t *e;
223   char from_name[MAX_STRING_SIZE];
224   char to_name[MAX_STRING_SIZE];
225   node_t *from, *to;
226   connection_t *other;
227   avl_node_t *node;
228 cp
229   if(sscanf(c->buffer, "%*d %*lx "MAX_STRING" "MAX_STRING"", from_name, to_name) != 2)
230     {
231       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE",
232              c->name, c->hostname);
233       return -1;
234     }
235
236   /* Check if names are valid */
237
238   if(check_id(from_name))
239     {
240       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name"));
241       return -1;
242     }
243
244   if(check_id(to_name))
245     {
246       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name"));
247       return -1;
248     }
249
250   if(seen_request(c->buffer))
251     return 0;
252
253   /* Lookup nodes */
254
255   from = lookup_node(from_name);
256   
257   if(!from)
258     {
259       if(debug_lvl >= DEBUG_PROTOCOL)
260         syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname);
261       return 0;
262     }
263
264   to = lookup_node(to_name);
265   
266   if(!to)
267     {
268       if(debug_lvl >= DEBUG_PROTOCOL)
269         syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname);
270       return 0;
271     }
272
273   /* Check if edge exists */
274   
275   e = lookup_edge(from, to);
276   
277   if(!e)
278   {
279     if(debug_lvl >= DEBUG_PROTOCOL)
280       syslog(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname);
281     return 0;
282   }
283
284   if(e->from.node == myself || e->to.node == myself)
285   {
286     if(debug_lvl >= DEBUG_PROTOCOL)
287       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_EDGE", c->name, c->hostname);
288     send_add_edge(c, e); /* Send back a correction */
289     return 0;
290   }
291
292   /* Tell the rest about the deleted edge */
293
294   for(node = connection_tree->head; node; node = node->next)
295     {
296       other = (connection_t *)node->data;
297       if(other->status.active && other != c)
298         send_request(other, "%s", c->buffer);
299     }
300
301   /* Delete the edge */
302   
303   edge_del(e);
304
305   /* Run MST before or after we tell the rest? */
306
307   graph();
308 cp
309   return 0;
310 }