rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 * $Id: gt_connect.c,v 1.55 2005/01/04 15:03:40 mkern Exp $
|
paulo@0
|
3 *
|
paulo@0
|
4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net)
|
paulo@0
|
5 *
|
paulo@0
|
6 * This program is free software; you can redistribute it and/or modify it
|
paulo@0
|
7 * under the terms of the GNU General Public License as published by the
|
paulo@0
|
8 * Free Software Foundation; either version 2, or (at your option) any
|
paulo@0
|
9 * later version.
|
paulo@0
|
10 *
|
paulo@0
|
11 * This program is distributed in the hope that it will be useful, but
|
paulo@0
|
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
paulo@0
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
paulo@0
|
14 * General Public License for more details.
|
paulo@0
|
15 */
|
paulo@0
|
16
|
paulo@0
|
17 #include "gt_gnutella.h"
|
paulo@0
|
18 #include "gt_version.h"
|
paulo@0
|
19
|
paulo@0
|
20 #include "gt_connect.h"
|
paulo@0
|
21 #include "gt_accept.h"
|
paulo@0
|
22 #include "gt_packet.h"
|
paulo@0
|
23
|
paulo@0
|
24 #include "gt_node.h"
|
paulo@0
|
25 #include "gt_node_list.h"
|
paulo@0
|
26 #include "gt_utils.h"
|
paulo@0
|
27
|
paulo@0
|
28 #include "gt_search.h"
|
paulo@0
|
29 #include "gt_netorg.h"
|
paulo@0
|
30
|
paulo@0
|
31 #include "gt_node_cache.h"
|
paulo@0
|
32
|
paulo@0
|
33 #include "message/gt_message.h" /* gnutella_start_connection */
|
paulo@0
|
34
|
paulo@0
|
35 /*****************************************************************************/
|
paulo@0
|
36
|
paulo@0
|
37 static void send_connect (int fd, input_id id, TCPC *c);
|
paulo@0
|
38 static void recv_headers (int fd, input_id id, TCPC *c);
|
paulo@0
|
39 static void send_response (int fd, input_id id, TCPC *c);
|
paulo@0
|
40 static BOOL send_final (TCPC *c);
|
paulo@0
|
41
|
paulo@0
|
42 /*****************************************************************************/
|
paulo@0
|
43
|
paulo@0
|
44 static BOOL handshake_timeout (TCPC *c)
|
paulo@0
|
45 {
|
paulo@0
|
46 GtNode *node = GT_NODE(c);
|
paulo@0
|
47
|
paulo@0
|
48 node->handshake_timer = 0;
|
paulo@0
|
49
|
paulo@0
|
50 if (!(node->state & GT_NODE_CONNECTED))
|
paulo@0
|
51 {
|
paulo@0
|
52 gt_node_disconnect (c);
|
paulo@0
|
53 return FALSE;
|
paulo@0
|
54 }
|
paulo@0
|
55
|
paulo@0
|
56 return FALSE;
|
paulo@0
|
57 }
|
paulo@0
|
58
|
paulo@0
|
59 void gnutella_set_handshake_timeout (TCPC *c, time_t delay)
|
paulo@0
|
60 {
|
paulo@0
|
61 timer_remove (GT_NODE(c)->handshake_timer);
|
paulo@0
|
62
|
paulo@0
|
63 GT_NODE(c)->handshake_timer = timer_add (delay,
|
paulo@0
|
64 (TimerCallback)handshake_timeout,
|
paulo@0
|
65 c);
|
paulo@0
|
66 }
|
paulo@0
|
67
|
paulo@0
|
68 int gt_connect (GtNode *node)
|
paulo@0
|
69 {
|
paulo@0
|
70 TCPC *c;
|
paulo@0
|
71
|
paulo@0
|
72 if (!node)
|
paulo@0
|
73 return -1;
|
paulo@0
|
74
|
paulo@0
|
75 #if 0
|
paulo@0
|
76 if (GT_CONN(node) != NULL)
|
paulo@0
|
77 {
|
paulo@0
|
78 GT->dbg (GT, "duplicate connection?: %p", GT_CONN(node));
|
paulo@0
|
79 return -1;
|
paulo@0
|
80 }
|
paulo@0
|
81
|
paulo@0
|
82 if (node->state != GT_NODE_DISCONNECTED)
|
paulo@0
|
83 {
|
paulo@0
|
84 GT->dbg (GT, "state = %i??", node->state);
|
paulo@0
|
85 return -1;
|
paulo@0
|
86 }
|
paulo@0
|
87 #endif
|
paulo@0
|
88
|
paulo@0
|
89 /* this must be called only on disconnected nodes */
|
paulo@0
|
90 assert (GT_CONN(node) == NULL);
|
paulo@0
|
91 assert (node->state == GT_NODE_DISCONNECTED);
|
paulo@0
|
92
|
paulo@0
|
93 #if 0
|
paulo@0
|
94 if (!conn_auth (c, TRUE))
|
paulo@0
|
95 return -1;
|
paulo@0
|
96 #endif
|
paulo@0
|
97
|
paulo@0
|
98 /* set this early: gt_netorg relies on this being set in order
|
paulo@0
|
99 * to check if it should access the gwebcaches */
|
paulo@0
|
100 node->start_connect_time = time (NULL);
|
paulo@0
|
101
|
paulo@0
|
102 /* make sure port is valid */
|
paulo@0
|
103 if (node->gt_port == 0)
|
paulo@0
|
104 {
|
paulo@0
|
105 GT->DBGFN (GT, "bad port on node %s", net_ip_str (node->ip));
|
paulo@0
|
106 return -1;
|
paulo@0
|
107 }
|
paulo@0
|
108
|
paulo@0
|
109 /* make outgoing connection */
|
paulo@0
|
110 if (!(c = tcp_open (node->ip, node->gt_port, FALSE)))
|
paulo@0
|
111 return -1;
|
paulo@0
|
112
|
paulo@0
|
113 gt_node_connect (node, c);
|
paulo@0
|
114
|
paulo@0
|
115 gt_node_state_set (node, GT_NODE_CONNECTING_1);
|
paulo@0
|
116 node->incoming = FALSE;
|
paulo@0
|
117
|
paulo@0
|
118 /* set the connection timeout */
|
paulo@0
|
119 gnutella_set_handshake_timeout (c, TIMEOUT_1 * SECONDS);
|
paulo@0
|
120
|
paulo@0
|
121 input_add (c->fd, c, INPUT_WRITE,
|
paulo@0
|
122 (InputCallback)send_connect, 0);
|
paulo@0
|
123
|
paulo@0
|
124 return c->fd;
|
paulo@0
|
125 }
|
paulo@0
|
126
|
paulo@0
|
127 static void send_connect (int fd, input_id id, TCPC *c)
|
paulo@0
|
128 {
|
paulo@0
|
129 if (net_sock_error (c->fd))
|
paulo@0
|
130 {
|
paulo@0
|
131 gt_node_disconnect (c);
|
paulo@0
|
132 return;
|
paulo@0
|
133 }
|
paulo@0
|
134
|
paulo@0
|
135 /* Send the connect string along with our headers */
|
paulo@0
|
136 if (!gnutella_send_connection_headers (c, "GNUTELLA CONNECT/0.6"))
|
paulo@0
|
137 {
|
paulo@0
|
138 gt_node_error (c, NULL);
|
paulo@0
|
139 gt_node_disconnect (c);
|
paulo@0
|
140 return;
|
paulo@0
|
141 }
|
paulo@0
|
142
|
paulo@0
|
143 /* we connected ok, so give the peer some more time */
|
paulo@0
|
144 gnutella_set_handshake_timeout (c, TIMEOUT_2 * SECONDS);
|
paulo@0
|
145
|
paulo@0
|
146 input_remove (id);
|
paulo@0
|
147 input_add (fd, c, INPUT_READ,
|
paulo@0
|
148 (InputCallback)recv_headers, 0);
|
paulo@0
|
149 }
|
paulo@0
|
150
|
paulo@0
|
151 BOOL gnutella_parse_response_headers (char *reply, Dataset **r_headers)
|
paulo@0
|
152 {
|
paulo@0
|
153 int code; /* 200, 404, ... */
|
paulo@0
|
154 char *response;
|
paulo@0
|
155 Dataset *headers = NULL;
|
paulo@0
|
156
|
paulo@0
|
157 response = string_sep (&reply, "\r\n");
|
paulo@0
|
158
|
paulo@0
|
159 if (!response)
|
paulo@0
|
160 return FALSE;
|
paulo@0
|
161
|
paulo@0
|
162 /* */ string_sep (&response, " "); /* shift past HTTP/1.1 */
|
paulo@0
|
163 code = ATOI (string_sep (&response, " ")); /* shift past 200 */
|
paulo@0
|
164
|
paulo@0
|
165 /* parse the headers */
|
paulo@0
|
166 gt_http_header_parse (reply, &headers);
|
paulo@0
|
167
|
paulo@0
|
168 if (r_headers)
|
paulo@0
|
169 *r_headers = headers;
|
paulo@0
|
170 else
|
paulo@0
|
171 dataset_clear (headers);
|
paulo@0
|
172
|
paulo@0
|
173 if (code >= 200 && code <= 299)
|
paulo@0
|
174 return TRUE;
|
paulo@0
|
175
|
paulo@0
|
176 return FALSE;
|
paulo@0
|
177 }
|
paulo@0
|
178
|
paulo@0
|
179 static time_t parse_uptime (Dataset *d)
|
paulo@0
|
180 {
|
paulo@0
|
181 char *str;
|
paulo@0
|
182 int days, hours, mins;
|
paulo@0
|
183 int n;
|
paulo@0
|
184
|
paulo@0
|
185 if (!(str = dataset_lookupstr (d, "uptime")))
|
paulo@0
|
186 return 0;
|
paulo@0
|
187
|
paulo@0
|
188 string_lower (str);
|
paulo@0
|
189
|
paulo@0
|
190 if ((n = sscanf (str, "%dd %dh %dm", &days, &hours, &mins)) != 3)
|
paulo@0
|
191 return 0;
|
paulo@0
|
192
|
paulo@0
|
193 if (HANDSHAKE_DEBUG)
|
paulo@0
|
194 {
|
paulo@0
|
195 GT->dbg (GT, "uptime parsed: %d days, %d hours, %d minutes",
|
paulo@0
|
196 days, hours, mins);
|
paulo@0
|
197 }
|
paulo@0
|
198
|
paulo@0
|
199 return days * EDAYS + hours * EHOURS + mins * EMINUTES;
|
paulo@0
|
200 }
|
paulo@0
|
201
|
paulo@0
|
202 /* look in a header field for nodes, and register them */
|
paulo@0
|
203 static void extract_nodes (Dataset *d, in_addr_t src,
|
paulo@0
|
204 const char *field, gt_node_class_t klass)
|
paulo@0
|
205 {
|
paulo@0
|
206 char *str;
|
paulo@0
|
207 char *value;
|
paulo@0
|
208 time_t now;
|
paulo@0
|
209
|
paulo@0
|
210 now = time (NULL);
|
paulo@0
|
211
|
paulo@0
|
212 if (!(str = dataset_lookupstr (d, field)))
|
paulo@0
|
213 return;
|
paulo@0
|
214
|
paulo@0
|
215 while ((value = string_sep (&str, ",")))
|
paulo@0
|
216 {
|
paulo@0
|
217 in_addr_t ip;
|
paulo@0
|
218 in_port_t port;
|
paulo@0
|
219
|
paulo@0
|
220 ip = net_ip (string_sep (&value, ":"));
|
paulo@0
|
221 port = ATOI (value);
|
paulo@0
|
222
|
paulo@0
|
223 if (port == (in_port_t) -1 || port == 0)
|
paulo@0
|
224 continue;
|
paulo@0
|
225
|
paulo@0
|
226 if (ip == INADDR_NONE || ip == 0)
|
paulo@0
|
227 continue;
|
paulo@0
|
228
|
paulo@0
|
229 if (gt_is_local_ip (ip, src))
|
paulo@0
|
230 continue;
|
paulo@0
|
231
|
paulo@0
|
232 gt_node_cache_add_ipv4 (ip, port, klass, now, 0, src);
|
paulo@0
|
233 }
|
paulo@0
|
234
|
paulo@0
|
235 gt_node_cache_trace ();
|
paulo@0
|
236 }
|
paulo@0
|
237
|
paulo@0
|
238 static void recv_headers (int fd, input_id id, TCPC *c)
|
paulo@0
|
239 {
|
paulo@0
|
240 FDBuf *buf;
|
paulo@0
|
241 char *response;
|
paulo@0
|
242 size_t response_len = 0;
|
paulo@0
|
243 int n;
|
paulo@0
|
244 BOOL ok;
|
paulo@0
|
245 time_t uptime;
|
paulo@0
|
246 GtNode *node = GT_NODE(c);
|
paulo@0
|
247
|
paulo@0
|
248 buf = tcp_readbuf (c);
|
paulo@0
|
249
|
paulo@0
|
250 if ((n = fdbuf_delim (buf, "\n")) < 0)
|
paulo@0
|
251 {
|
paulo@0
|
252 GT->DBGFN (GT, "error reading headers: %s", GIFT_NETERROR ());
|
paulo@0
|
253 gt_node_disconnect (c);
|
paulo@0
|
254 return;
|
paulo@0
|
255 }
|
paulo@0
|
256
|
paulo@0
|
257 if (gt_fdbuf_full (buf))
|
paulo@0
|
258 {
|
paulo@0
|
259 gt_node_disconnect (c);
|
paulo@0
|
260 return;
|
paulo@0
|
261 }
|
paulo@0
|
262
|
paulo@0
|
263 if (n > 0)
|
paulo@0
|
264 return;
|
paulo@0
|
265
|
paulo@0
|
266 response = fdbuf_data (buf, &response_len);
|
paulo@0
|
267 if (!gt_http_header_terminated (response, response_len))
|
paulo@0
|
268 return;
|
paulo@0
|
269
|
paulo@0
|
270 fdbuf_release (buf);
|
paulo@0
|
271
|
paulo@0
|
272 if (HANDSHAKE_DEBUG)
|
paulo@0
|
273 GT->DBGSOCK (GT, c, "node handshake response:\n%s", response);
|
paulo@0
|
274
|
paulo@0
|
275 /* parse and store the response */
|
paulo@0
|
276 ok = gnutella_parse_response_headers (response, &node->hdr);
|
paulo@0
|
277
|
paulo@0
|
278 /* extract nodes */
|
paulo@0
|
279 extract_nodes (node->hdr, node->ip, "x-try-ultrapeers", GT_NODE_ULTRA);
|
paulo@0
|
280 extract_nodes (node->hdr, node->ip, "x-try", GT_NODE_NONE);
|
paulo@0
|
281
|
paulo@0
|
282 /* grab the uptime from the "Uptime: " header and update this node */
|
paulo@0
|
283 if ((uptime = parse_uptime (node->hdr)) > 0)
|
paulo@0
|
284 {
|
paulo@0
|
285 gt_node_cache_add_ipv4 (node->ip, node->gt_port,
|
paulo@0
|
286 GT_NODE_ULTRA, time (NULL), uptime, node->ip);
|
paulo@0
|
287
|
paulo@0
|
288 /* XXX: remove the item immediately so we trigger the side effect of
|
paulo@0
|
289 * adding this node to the stable list */
|
paulo@0
|
290 gt_node_cache_del_ipv4 (node->ip, node->gt_port);
|
paulo@0
|
291 }
|
paulo@0
|
292
|
paulo@0
|
293 if (!ok)
|
paulo@0
|
294 {
|
paulo@0
|
295 gt_node_disconnect (c);
|
paulo@0
|
296 return;
|
paulo@0
|
297 }
|
paulo@0
|
298
|
paulo@0
|
299 input_remove (id);
|
paulo@0
|
300 input_add (fd, c, INPUT_WRITE,
|
paulo@0
|
301 (InputCallback)send_response, 0);
|
paulo@0
|
302 }
|
paulo@0
|
303
|
paulo@0
|
304 static void send_response (int fd, input_id id, TCPC *c)
|
paulo@0
|
305 {
|
paulo@0
|
306 if (net_sock_error (c->fd))
|
paulo@0
|
307 {
|
paulo@0
|
308 gt_node_error (c, NULL);
|
paulo@0
|
309 gt_node_disconnect (c);
|
paulo@0
|
310 return;
|
paulo@0
|
311 }
|
paulo@0
|
312
|
paulo@0
|
313 if (!gnutella_auth_connection (c))
|
paulo@0
|
314 {
|
paulo@0
|
315 gt_node_error (c, "[outgoing] connection not authorized");
|
paulo@0
|
316 gt_node_disconnect (c);
|
paulo@0
|
317 return;
|
paulo@0
|
318 }
|
paulo@0
|
319
|
paulo@0
|
320 if (!send_final (c))
|
paulo@0
|
321 {
|
paulo@0
|
322 gt_node_error (c, NULL);
|
paulo@0
|
323 GT->DBGSOCK (GT, c, "error at stage 3 of handshake");
|
paulo@0
|
324 gt_node_disconnect (c);
|
paulo@0
|
325 return;
|
paulo@0
|
326 }
|
paulo@0
|
327
|
paulo@0
|
328 /* ok, startup this connection */
|
paulo@0
|
329 input_remove (id);
|
paulo@0
|
330 input_add (fd, c, INPUT_WRITE,
|
paulo@0
|
331 (InputCallback)gnutella_start_connection, 0);
|
paulo@0
|
332 }
|
paulo@0
|
333
|
paulo@0
|
334 /*****************************************************************************/
|
paulo@0
|
335
|
paulo@0
|
336 static GtNode *append_node (TCPC *c, GtNode *node, String *s)
|
paulo@0
|
337 {
|
paulo@0
|
338 if (s->str[s->len - 1] != ' ')
|
paulo@0
|
339 string_append (s, ",");
|
paulo@0
|
340
|
paulo@0
|
341 string_appendf (s, "%s:%hu", net_ip_str (node->ip), node->gt_port);
|
paulo@0
|
342 return NULL;
|
paulo@0
|
343 }
|
paulo@0
|
344
|
paulo@0
|
345 static void append_crawler_headers (String *msg)
|
paulo@0
|
346 {
|
paulo@0
|
347 if (gt_conn_length (GT_NODE_ULTRA, GT_NODE_CONNECTED) > 0)
|
paulo@0
|
348 {
|
paulo@0
|
349 string_append (msg, "Peers: ");
|
paulo@0
|
350 gt_conn_foreach (GT_CONN_FOREACH(append_node), msg,
|
paulo@0
|
351 GT_NODE_ULTRA, GT_NODE_CONNECTED, 0);
|
paulo@0
|
352 string_append (msg, "\r\n");
|
paulo@0
|
353 }
|
paulo@0
|
354
|
paulo@0
|
355 if (GT_SELF->klass & GT_NODE_ULTRA &&
|
paulo@0
|
356 gt_conn_length (GT_NODE_LEAF, GT_NODE_CONNECTED) > 0)
|
paulo@0
|
357 {
|
paulo@0
|
358 string_append (msg, "Leaves: ");
|
paulo@0
|
359 gt_conn_foreach (GT_CONN_FOREACH(append_node), msg,
|
paulo@0
|
360 GT_NODE_LEAF, GT_NODE_CONNECTED, 0);
|
paulo@0
|
361 string_append (msg, "\r\n");
|
paulo@0
|
362 }
|
paulo@0
|
363 }
|
paulo@0
|
364
|
paulo@0
|
365 BOOL gnutella_send_connection_headers (TCPC *c, const char *header)
|
paulo@0
|
366 {
|
paulo@0
|
367 String *msg;
|
paulo@0
|
368
|
paulo@0
|
369 if (!(msg = string_new (NULL, 0, 0, TRUE)))
|
paulo@0
|
370 return FALSE;
|
paulo@0
|
371
|
paulo@0
|
372 string_appendf (msg, "%s\r\n", header);
|
paulo@0
|
373
|
paulo@0
|
374 string_append (msg, "X-Query-Routing: 0.1\r\n");
|
paulo@0
|
375 string_appendf (msg, "X-Ultrapeer: %s\r\n",
|
paulo@0
|
376 (GT_SELF->klass & GT_NODE_ULTRA) ? "True" : "False");
|
paulo@0
|
377
|
paulo@0
|
378 /* append the client and version we are using */
|
paulo@0
|
379 string_appendf (msg, "User-Agent: %s\r\n", gt_version ());
|
paulo@0
|
380
|
paulo@0
|
381 /* Add a header describing the remote IP of the peer */
|
paulo@0
|
382 string_appendf (msg, "Remote-IP: %s\r\n", net_peer_ip (c->fd));
|
paulo@0
|
383
|
paulo@0
|
384 /* let remote end know it's ok to send vendor messages */
|
paulo@0
|
385 string_appendf (msg, "Vendor-Message: 0.1\r\n");
|
paulo@0
|
386
|
paulo@0
|
387 /* support transmission of pings/pongs with GGEP appended */
|
paulo@0
|
388 string_append (msg, "GGEP: 0.5\r\n");
|
paulo@0
|
389
|
paulo@0
|
390 /* If this is the limewire crawler, append "Peers: " and "Leaves: "
|
paulo@0
|
391 * headers and close the connection */
|
paulo@0
|
392 if (!c->outgoing && dataset_lookupstr (GT_NODE(c)->hdr, "crawler"))
|
paulo@0
|
393 append_crawler_headers (msg);
|
paulo@0
|
394
|
paulo@0
|
395 /* append willingness to receive compressed data */
|
paulo@0
|
396 string_append (msg, "Accept-Encoding: deflate\r\n");
|
paulo@0
|
397
|
paulo@0
|
398 /* check whether the remote node sent us Accept-Encoding: deflate
|
paulo@0
|
399 * already */
|
paulo@0
|
400 gnutella_mark_compression (GT_NODE(c));
|
paulo@0
|
401
|
paulo@0
|
402 /* compress data if we must */
|
paulo@0
|
403 if (GT_NODE(c)->tx_deflated)
|
paulo@0
|
404 string_append (msg, "Content-Encoding: deflate\r\n");
|
paulo@0
|
405
|
paulo@0
|
406 /* Add message terminator */
|
paulo@0
|
407 string_append (msg, "\r\n");
|
paulo@0
|
408
|
paulo@0
|
409 if (HANDSHAKE_DEBUG)
|
paulo@0
|
410 GT->DBGSOCK (GT, c, "sending node headers:\n%s", msg->str);
|
paulo@0
|
411
|
paulo@0
|
412 if (tcp_send (c, msg->str, msg->len) <= 0)
|
paulo@0
|
413 {
|
paulo@0
|
414 string_free (msg);
|
paulo@0
|
415 return FALSE;
|
paulo@0
|
416 }
|
paulo@0
|
417
|
paulo@0
|
418 string_free (msg);
|
paulo@0
|
419 return TRUE;
|
paulo@0
|
420 }
|
paulo@0
|
421
|
paulo@0
|
422 static BOOL send_final (TCPC *c)
|
paulo@0
|
423 {
|
paulo@0
|
424 String *s;
|
paulo@0
|
425 int ret;
|
paulo@0
|
426 int len;
|
paulo@0
|
427
|
paulo@0
|
428 if (!(s = string_new (NULL, 0, 0, TRUE)))
|
paulo@0
|
429 return FALSE;
|
paulo@0
|
430
|
paulo@0
|
431 /* append header acceptance line */
|
paulo@0
|
432 string_append (s, "GNUTELLA/0.6 200 OK\r\n");
|
paulo@0
|
433
|
paulo@0
|
434 /* mark the connection as complete */
|
paulo@0
|
435 gnutella_mark_compression (GT_NODE(c));
|
paulo@0
|
436
|
paulo@0
|
437 if (GT_NODE(c)->tx_deflated)
|
paulo@0
|
438 string_append (s, "Content-Encoding: deflate\r\n");
|
paulo@0
|
439
|
paulo@0
|
440 /* append msg terminator */
|
paulo@0
|
441 string_append (s, "\r\n");
|
paulo@0
|
442
|
paulo@0
|
443 if (HANDSHAKE_DEBUG)
|
paulo@0
|
444 GT->DBGSOCK (GT, c, "sending final handshake:\n%s", s->str);
|
paulo@0
|
445
|
paulo@0
|
446 len = s->len;
|
paulo@0
|
447 ret = tcp_send (c, s->str, s->len);
|
paulo@0
|
448
|
paulo@0
|
449 string_free (s);
|
paulo@0
|
450
|
paulo@0
|
451 if (ret != len)
|
paulo@0
|
452 return FALSE;
|
paulo@0
|
453
|
paulo@0
|
454 return TRUE;
|
paulo@0
|
455 }
|
paulo@0
|
456
|
paulo@0
|
457 /*****************************************************************************/
|
paulo@0
|
458 /* CONNECTABILITY TESTING */
|
paulo@0
|
459
|
paulo@0
|
460 static void connect_test_result (GtNode *node, TCPC *c, BOOL success)
|
paulo@0
|
461 {
|
paulo@0
|
462 GT->DBGFN (GT, "connect test to %s %s", net_ip_str (node->ip),
|
paulo@0
|
463 (success ? "succeeded" : "failed"));
|
paulo@0
|
464
|
paulo@0
|
465 node->firewalled = (success ? FALSE : TRUE);
|
paulo@0
|
466 node->verified = TRUE;
|
paulo@0
|
467
|
paulo@0
|
468 if (c)
|
paulo@0
|
469 {
|
paulo@0
|
470 tcp_close (c);
|
paulo@0
|
471 node->gt_port_verify = NULL;
|
paulo@0
|
472 }
|
paulo@0
|
473 }
|
paulo@0
|
474
|
paulo@0
|
475 static void test_connectable (int fd, input_id id, TCPC *c)
|
paulo@0
|
476 {
|
paulo@0
|
477 GtNode *node;
|
paulo@0
|
478
|
paulo@0
|
479 node = c->udata;
|
paulo@0
|
480
|
paulo@0
|
481 if (net_sock_error (c->fd))
|
paulo@0
|
482 {
|
paulo@0
|
483 connect_test_result (node, c, FALSE);
|
paulo@0
|
484 return;
|
paulo@0
|
485 }
|
paulo@0
|
486
|
paulo@0
|
487 /*
|
paulo@0
|
488 * Send two newlines, because some firewalls will let connections pass
|
paulo@0
|
489 * through, but no data.
|
paulo@0
|
490 */
|
paulo@0
|
491 tcp_send (c, "\n\n", 2);
|
paulo@0
|
492 connect_test_result (node, c, TRUE);
|
paulo@0
|
493 }
|
paulo@0
|
494
|
paulo@0
|
495 /*
|
paulo@0
|
496 * Test if the port of a peer we are connected to is connectable. This lets a
|
paulo@0
|
497 * node know if it's firewalled. We could use this info to mangle the 'push'
|
paulo@0
|
498 * flag on query hits from this node if it is a leaf.
|
paulo@0
|
499 *
|
paulo@0
|
500 * Mangling query hits would break any future checksum or signing algorithm on
|
paulo@0
|
501 * query hits though, so that isn't done.
|
paulo@0
|
502 */
|
paulo@0
|
503 void gt_connect_test (GtNode *node, in_port_t port)
|
paulo@0
|
504 {
|
paulo@0
|
505 TCPC *new_c;
|
paulo@0
|
506
|
paulo@0
|
507 if (!port)
|
paulo@0
|
508 {
|
paulo@0
|
509 node->firewalled = TRUE;
|
paulo@0
|
510 return;
|
paulo@0
|
511 }
|
paulo@0
|
512
|
paulo@0
|
513 /* this needs some kind of local mode switch */
|
paulo@0
|
514 #if 0
|
paulo@0
|
515 if (net_match_host (GT_NODE(c)->ip, "LOCAL"))
|
paulo@0
|
516 {
|
paulo@0
|
517 GT_NODE(c)->firewalled = TRUE;
|
paulo@0
|
518 return;
|
paulo@0
|
519 }
|
paulo@0
|
520 #endif
|
paulo@0
|
521
|
paulo@0
|
522 if (!node->incoming)
|
paulo@0
|
523 return;
|
paulo@0
|
524
|
paulo@0
|
525 GT->DBGFN (GT, "starting connect test on %s:%hu",
|
paulo@0
|
526 net_ip_str (node->ip), port);
|
paulo@0
|
527
|
paulo@0
|
528 if (!(new_c = tcp_open (node->ip, port, FALSE)))
|
paulo@0
|
529 {
|
paulo@0
|
530 GT->DBGFN (GT, "failed to open test connection to %s:%hu",
|
paulo@0
|
531 net_ip_str (node->ip), node->gt_port);
|
paulo@0
|
532 return;
|
paulo@0
|
533 }
|
paulo@0
|
534
|
paulo@0
|
535 if (node->gt_port_verify)
|
paulo@0
|
536 tcp_close (node->gt_port_verify);
|
paulo@0
|
537
|
paulo@0
|
538 /* keep track of this connection */
|
paulo@0
|
539 node->gt_port_verify = new_c;
|
paulo@0
|
540 new_c->udata = node;
|
paulo@0
|
541
|
paulo@0
|
542 input_add (new_c->fd, new_c, INPUT_WRITE,
|
paulo@0
|
543 (InputCallback)test_connectable, TIMEOUT_DEF);
|
paulo@0
|
544 }
|