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