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