Remember sockaddrs of listening sockets, use appropriate one when sending
[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.2 2002/02/18 16:25:18 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 %s %s %s %s %s %s %s %s %lx %d", ADD_EDGE,
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 "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   /* Lookup nodes */
117
118   from = lookup_node(from_name);
119   
120   if(!from)
121     {
122       from = new_node();
123       from->name = xstrdup(from_name);
124       node_add(from);
125     }
126
127   to = lookup_node(to_name);
128   
129   if(!to)
130     {
131       to = new_node();
132       to->name = xstrdup(to_name);
133       node_add(to);
134     }
135
136   /* Convert addresses */
137   
138   from_tcpaddress = str2sockaddr(from_address, from_tcpport);
139   from_udpaddress = str2sockaddr(from_address, from_udpport);
140   to_tcpaddress = str2sockaddr(to_address, to_tcpport);
141   to_udpaddress = str2sockaddr(to_address, to_udpport);
142
143   /* Check if edge already exists */
144   
145   e = lookup_edge(from, to);
146   
147   if(e)
148   {
149     if(e->weight != weight || e->options != options
150        || ((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)))
151        || ((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)))
152       )
153     {
154       if(from == myself || to == myself)
155       {
156         if(debug_lvl >= DEBUG_PROTOCOL)
157           syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not match existing entry"), "ADD_EDGE", c->name, c->hostname);
158         send_add_edge(c, e);
159         return 0;
160       }
161       else
162       {
163         if(debug_lvl >= DEBUG_PROTOCOL)
164           syslog(LOG_WARNING, _("Got %s from %s (%s) which does not match existing entry"), "ADD_EDGE", c->name, c->hostname);
165         edge_del(e);
166       }
167     }
168     else
169       return 0;
170   }
171   else if(from == myself || to == myself)
172   {
173     if(debug_lvl >= DEBUG_PROTOCOL)
174       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself which does not exist"), "ADD_EDGE", c->name, c->hostname);
175     e = new_edge();
176     e->from.node = from;
177     e->to.node = to;
178     send_del_edge(c, e);
179     free_edge(e);
180     return 0;
181   }
182
183
184
185   e = new_edge();
186   e->from.node = from;
187   e->from.tcpaddress = from_tcpaddress;
188   e->from.udpaddress = from_udpaddress;
189   e->to.node = to;
190   e->to.tcpaddress = to_tcpaddress;
191   e->to.udpaddress = to_udpaddress;
192   e->options = options;
193   e->weight = weight;
194   edge_add(e);
195
196   /* Tell the rest about the new edge */
197
198   for(node = connection_tree->head; node; node = node->next)
199     {
200       other = (connection_t *)node->data;
201       if(other->status.active && other != c)
202         send_add_edge(other, e);
203     }
204
205   /* Run MST before or after we tell the rest? */
206
207   graph();
208 cp
209   return 0;
210 }
211
212 int send_del_edge(connection_t *c, edge_t *e)
213 {
214 cp
215   return send_request(c, "%d %s %s", DEL_EDGE,
216                       e->from.node->name, e->to.node->name);
217 }
218
219 int del_edge_h(connection_t *c)
220 {
221   edge_t *e;
222   char from_name[MAX_STRING_SIZE];
223   char to_name[MAX_STRING_SIZE];
224   node_t *from, *to;
225   connection_t *other;
226   avl_node_t *node;
227 cp
228   if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING"", from_name, to_name) != 2)
229     {
230       syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "DEL_EDGE",
231              c->name, c->hostname);
232       return -1;
233     }
234
235   /* Check if names are valid */
236
237   if(check_id(from_name))
238     {
239       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name"));
240       return -1;
241     }
242
243   if(check_id(to_name))
244     {
245       syslog(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_EDGE", c->name, c->hostname, _("invalid name"));
246       return -1;
247     }
248
249   /* Lookup nodes */
250
251   from = lookup_node(from_name);
252   
253   if(!from)
254     {
255       if(debug_lvl >= DEBUG_PROTOCOL)
256         syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname);
257       return 0;
258     }
259
260   to = lookup_node(to_name);
261   
262   if(!to)
263     {
264       if(debug_lvl >= DEBUG_PROTOCOL)
265         syslog(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname);
266       return 0;
267     }
268
269   /* Check if edge exists */
270   
271   e = lookup_edge(from, to);
272   
273   if(!e)
274   {
275     if(debug_lvl >= DEBUG_PROTOCOL)
276       syslog(LOG_WARNING, _("Got %s from %s (%s) which does not appear in the edge tree"), "DEL_EDGE", c->name, c->hostname);
277     return 0;
278   }
279
280   if(e->from.node == myself || e->to.node == myself)
281   {
282     if(debug_lvl >= DEBUG_PROTOCOL)
283       syslog(LOG_WARNING, _("Got %s from %s (%s) for ourself"), "DEL_EDGE", c->name, c->hostname);
284     send_add_edge(c, e); /* Send back a correction */
285     return 0;
286   }
287
288   /* Tell the rest about the deleted edge */
289
290   for(node = connection_tree->head; node; node = node->next)
291     {
292       other = (connection_t *)node->data;
293       if(other->status.active && other != c)
294         send_del_edge(other, e);
295     }
296
297   /* Delete the edge */
298   
299   edge_del(e);
300
301   /* Run MST before or after we tell the rest? */
302
303   graph();
304 cp
305   return 0;
306 }