rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 * $Id: gt_bind.c,v 1.6 2004/04/17 06:08:14 hipnod Exp $
|
paulo@0
|
3 *
|
paulo@0
|
4 * Copyright (C) 2001-2004 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_node.h"
|
paulo@0
|
19 #include "gt_node_list.h"
|
paulo@0
|
20
|
paulo@0
|
21 #include "gt_accept.h"
|
paulo@0
|
22 #include "gt_bind.h"
|
paulo@0
|
23 #include "gt_packet.h"
|
paulo@0
|
24 #include "gt_share_state.h"
|
paulo@0
|
25
|
paulo@0
|
26 #include "transfer/push_proxy.h"
|
paulo@0
|
27
|
paulo@0
|
28 /*****************************************************************************/
|
paulo@0
|
29
|
paulo@0
|
30 /* global node pointer for this machine */
|
paulo@0
|
31 GtNode *GT_SELF;
|
paulo@0
|
32
|
paulo@0
|
33 /*****************************************************************************/
|
paulo@0
|
34
|
paulo@0
|
35 /* how often to retest the firewalled status of this node */
|
paulo@0
|
36 #define FW_RETEST_INTERVAL (60 * MINUTES)
|
paulo@0
|
37
|
paulo@0
|
38 /* maximum amount of time before last connect read from disk before
|
paulo@0
|
39 * reassuming this node is firewalled on startup */
|
paulo@0
|
40 #define FW_MAX_RETEST_TIME (7 * EDAYS)
|
paulo@0
|
41
|
paulo@0
|
42 /*****************************************************************************/
|
paulo@0
|
43
|
paulo@0
|
44 /* time at which this node started running */
|
paulo@0
|
45 static time_t start_time;
|
paulo@0
|
46
|
paulo@0
|
47 /* last time we got a connection on this host */
|
paulo@0
|
48 static time_t last_connect;
|
paulo@0
|
49
|
paulo@0
|
50 /* retest firewalled status every so often */
|
paulo@0
|
51 static timer_id fw_test_timer;
|
paulo@0
|
52
|
paulo@0
|
53 /*****************************************************************************/
|
paulo@0
|
54
|
paulo@0
|
55 static char *fw_file (void)
|
paulo@0
|
56 {
|
paulo@0
|
57 return gift_conf_path ("Gnutella/fwstatus");
|
paulo@0
|
58 }
|
paulo@0
|
59
|
paulo@0
|
60 static void save_fw_status (void)
|
paulo@0
|
61 {
|
paulo@0
|
62 FILE *f;
|
paulo@0
|
63
|
paulo@0
|
64 if (!(f = fopen (fw_file (), "w")))
|
paulo@0
|
65 return;
|
paulo@0
|
66
|
paulo@0
|
67 /*
|
paulo@0
|
68 * Store the last successful time of connect along with the port.
|
paulo@0
|
69 */
|
paulo@0
|
70 fprintf (f, "%lu %hu\n", last_connect, GT_SELF->gt_port);
|
paulo@0
|
71
|
paulo@0
|
72 fclose (f);
|
paulo@0
|
73 }
|
paulo@0
|
74
|
paulo@0
|
75 /* returns whether or not the node is firewalled */
|
paulo@0
|
76 static BOOL load_fw_status (in_port_t port)
|
paulo@0
|
77 {
|
paulo@0
|
78 FILE *f;
|
paulo@0
|
79 char buf[RW_BUFFER];
|
paulo@0
|
80 time_t last_time;
|
paulo@0
|
81 in_port_t last_port;
|
paulo@0
|
82
|
paulo@0
|
83 if (!(f = fopen (fw_file (), "r")))
|
paulo@0
|
84 return TRUE;
|
paulo@0
|
85
|
paulo@0
|
86 if (fgets (buf, sizeof (buf) - 1, f) == NULL)
|
paulo@0
|
87 {
|
paulo@0
|
88 fclose (f);
|
paulo@0
|
89 return TRUE;
|
paulo@0
|
90 }
|
paulo@0
|
91
|
paulo@0
|
92 fclose (f);
|
paulo@0
|
93
|
paulo@0
|
94 /* Store the time of the last successful connect, so
|
paulo@0
|
95 * > 0 means _not_ firewalled */
|
paulo@0
|
96 if (sscanf (buf, "%lu %hu", &last_time, &last_port) != 2)
|
paulo@0
|
97 return TRUE;
|
paulo@0
|
98
|
paulo@0
|
99 /* if we got a connection within a recent time at some point with this
|
paulo@0
|
100 * port, mark not firewalled */
|
paulo@0
|
101 if ((last_time > 0 && last_time < FW_MAX_RETEST_TIME) &&
|
paulo@0
|
102 last_port == port)
|
paulo@0
|
103 {
|
paulo@0
|
104 last_connect = last_time;
|
paulo@0
|
105 return FALSE;
|
paulo@0
|
106 }
|
paulo@0
|
107
|
paulo@0
|
108 return TRUE;
|
paulo@0
|
109 }
|
paulo@0
|
110
|
paulo@0
|
111 static gt_node_class_t read_class (void)
|
paulo@0
|
112 {
|
paulo@0
|
113 char *klass;
|
paulo@0
|
114
|
paulo@0
|
115 klass = gt_config_get_str ("main/class");
|
paulo@0
|
116
|
paulo@0
|
117 if (klass && strstr (klass, "ultra"))
|
paulo@0
|
118 return GT_NODE_ULTRA;
|
paulo@0
|
119
|
paulo@0
|
120 return GT_NODE_LEAF;
|
paulo@0
|
121 }
|
paulo@0
|
122
|
paulo@0
|
123 static void setup_self (GtNode *node, TCPC *c, in_port_t port)
|
paulo@0
|
124 {
|
paulo@0
|
125 /* load the firewalled status of this port */
|
paulo@0
|
126 node->firewalled = load_fw_status (port);
|
paulo@0
|
127
|
paulo@0
|
128 /* attach the connection to this node */
|
paulo@0
|
129 gt_node_connect (node, c);
|
paulo@0
|
130 node->gt_port = port;
|
paulo@0
|
131
|
paulo@0
|
132 /* load the class for this node */
|
paulo@0
|
133 node->klass = read_class ();
|
paulo@0
|
134
|
paulo@0
|
135 input_add (c->fd, c, INPUT_READ,
|
paulo@0
|
136 (InputCallback)gnutella_handle_incoming, FALSE);
|
paulo@0
|
137 }
|
paulo@0
|
138
|
paulo@0
|
139 static GtNode *bind_gnutella_port (in_port_t port)
|
paulo@0
|
140 {
|
paulo@0
|
141 GtNode *node;
|
paulo@0
|
142 TCPC *c;
|
paulo@0
|
143
|
paulo@0
|
144 GT->DBGFN (GT, "entered");
|
paulo@0
|
145
|
paulo@0
|
146 if (!(node = gt_node_new ()))
|
paulo@0
|
147 return NULL;
|
paulo@0
|
148
|
paulo@0
|
149 /* assume sane defaults in case the bind fails */
|
paulo@0
|
150 node->gt_port = 0;
|
paulo@0
|
151 node->firewalled = TRUE;
|
paulo@0
|
152 node->klass = GT_NODE_LEAF;
|
paulo@0
|
153
|
paulo@0
|
154 if (!port || !(c = tcp_bind (port, FALSE)))
|
paulo@0
|
155 {
|
paulo@0
|
156 GT->warn (GT, "Failed binding port %d, setting firewalled", port);
|
paulo@0
|
157 return node;
|
paulo@0
|
158 }
|
paulo@0
|
159
|
paulo@0
|
160 GT->dbg (GT, "bound to port %d", port);
|
paulo@0
|
161
|
paulo@0
|
162 /* setup what will become GT_SELF structure */
|
paulo@0
|
163 setup_self (node, c, port);
|
paulo@0
|
164
|
paulo@0
|
165 return node;
|
paulo@0
|
166 }
|
paulo@0
|
167
|
paulo@0
|
168 static void setup_listening_port (in_port_t port)
|
paulo@0
|
169 {
|
paulo@0
|
170 GT_SELF = bind_gnutella_port (port);
|
paulo@0
|
171
|
paulo@0
|
172 /*
|
paulo@0
|
173 * If running in local mode, let the user set firewalled status in
|
paulo@0
|
174 * GNUTELLA_LOCAL_FW. Not sure if this is a good idea, but it makes
|
paulo@0
|
175 * testing easier.
|
paulo@0
|
176 */
|
paulo@0
|
177 if (GNUTELLA_LOCAL_MODE)
|
paulo@0
|
178 {
|
paulo@0
|
179 if (GNUTELLA_LOCAL_FW)
|
paulo@0
|
180 GT_SELF->firewalled = TRUE;
|
paulo@0
|
181 else
|
paulo@0
|
182 GT_SELF->firewalled = FALSE;
|
paulo@0
|
183 }
|
paulo@0
|
184 }
|
paulo@0
|
185
|
paulo@0
|
186 /*****************************************************************************/
|
paulo@0
|
187
|
paulo@0
|
188 BOOL gt_bind_is_firewalled (void)
|
paulo@0
|
189 {
|
paulo@0
|
190 if (!GT_SELF->firewalled)
|
paulo@0
|
191 return FALSE;
|
paulo@0
|
192
|
paulo@0
|
193 /*
|
paulo@0
|
194 * Pretend we are not firewalled at the beginning in order
|
paulo@0
|
195 * to possibly get more connections, to prove we are not firewalled.
|
paulo@0
|
196 */
|
paulo@0
|
197 if (gt_uptime () < 10 * EMINUTES)
|
paulo@0
|
198 return FALSE;
|
paulo@0
|
199
|
paulo@0
|
200 /* we are firewalled */
|
paulo@0
|
201 return TRUE;
|
paulo@0
|
202 }
|
paulo@0
|
203
|
paulo@0
|
204 void gt_bind_clear_firewalled (void)
|
paulo@0
|
205 {
|
paulo@0
|
206 time (&last_connect);
|
paulo@0
|
207 GT_SELF->firewalled = FALSE;
|
paulo@0
|
208 }
|
paulo@0
|
209
|
paulo@0
|
210 static BOOL fwtest_node (GtNode *node)
|
paulo@0
|
211 {
|
paulo@0
|
212 GtPacket *pkt;
|
paulo@0
|
213 BOOL ret;
|
paulo@0
|
214
|
paulo@0
|
215 if (!GT_SELF->firewalled)
|
paulo@0
|
216 return FALSE;
|
paulo@0
|
217
|
paulo@0
|
218 if (!(pkt = gt_packet_vendor (GT_VMSG_TCP_CONNECT_BACK)))
|
paulo@0
|
219 return FALSE;
|
paulo@0
|
220
|
paulo@0
|
221 gt_packet_put_port (pkt, GT_SELF->gt_port);
|
paulo@0
|
222 GT->DBGSOCK (GT, GT_CONN(node), "fwtesting");
|
paulo@0
|
223
|
paulo@0
|
224 ret = gt_node_send_if_supported (node, pkt);
|
paulo@0
|
225 gt_packet_free (pkt);
|
paulo@0
|
226
|
paulo@0
|
227 return ret;
|
paulo@0
|
228 }
|
paulo@0
|
229
|
paulo@0
|
230 /*****************************************************************************/
|
paulo@0
|
231
|
paulo@0
|
232 static void push_proxy_request (GtNode *node)
|
paulo@0
|
233 {
|
paulo@0
|
234 GtPacket *pkt;
|
paulo@0
|
235
|
paulo@0
|
236 if (!(pkt = gt_packet_vendor (GT_VMSG_PUSH_PROXY_REQ)))
|
paulo@0
|
237 return;
|
paulo@0
|
238
|
paulo@0
|
239 /* the GUID of the PushProxyRequest must be our client identifier */
|
paulo@0
|
240 gt_packet_set_guid (pkt, GT_SELF_GUID);
|
paulo@0
|
241
|
paulo@0
|
242 gt_node_send_if_supported (node, pkt);
|
paulo@0
|
243
|
paulo@0
|
244 gt_packet_free (pkt);
|
paulo@0
|
245 }
|
paulo@0
|
246
|
paulo@0
|
247 /*****************************************************************************/
|
paulo@0
|
248
|
paulo@0
|
249 /*
|
paulo@0
|
250 * Called when a new connection to a node has completed.
|
paulo@0
|
251 */
|
paulo@0
|
252 void gt_bind_completed_connection (GtNode *node)
|
paulo@0
|
253 {
|
paulo@0
|
254 if (node->vmsgs_sent && dataset_length (node->vmsgs_supported) > 0)
|
paulo@0
|
255 return;
|
paulo@0
|
256
|
paulo@0
|
257 node->vmsgs_sent = TRUE;
|
paulo@0
|
258
|
paulo@0
|
259 fwtest_node (node);
|
paulo@0
|
260 push_proxy_request (node);
|
paulo@0
|
261 }
|
paulo@0
|
262
|
paulo@0
|
263 /*****************************************************************************/
|
paulo@0
|
264
|
paulo@0
|
265 static GtNode *retest (TCPC *c, GtNode *node, void *udata)
|
paulo@0
|
266 {
|
paulo@0
|
267 /*
|
paulo@0
|
268 * Only clear firewalled status once and if the node supports
|
paulo@0
|
269 * the TcpConnectBack message.
|
paulo@0
|
270 */
|
paulo@0
|
271 if (fwtest_node (node) && GT_SELF->firewalled == FALSE)
|
paulo@0
|
272 {
|
paulo@0
|
273 GT->DBGFN (GT, "clearing firewalled status");
|
paulo@0
|
274 GT_SELF->firewalled = TRUE;
|
paulo@0
|
275 }
|
paulo@0
|
276
|
paulo@0
|
277 return NULL;
|
paulo@0
|
278 }
|
paulo@0
|
279
|
paulo@0
|
280 static BOOL fw_test (void *udata)
|
paulo@0
|
281 {
|
paulo@0
|
282 gt_conn_foreach (retest, NULL,
|
paulo@0
|
283 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
|
paulo@0
|
284
|
paulo@0
|
285 return TRUE;
|
paulo@0
|
286 }
|
paulo@0
|
287
|
paulo@0
|
288 /*****************************************************************************/
|
paulo@0
|
289
|
paulo@0
|
290 time_t gt_uptime (void)
|
paulo@0
|
291 {
|
paulo@0
|
292 return start_time;
|
paulo@0
|
293 }
|
paulo@0
|
294
|
paulo@0
|
295 /*****************************************************************************/
|
paulo@0
|
296
|
paulo@0
|
297 void gt_bind_init (void)
|
paulo@0
|
298 {
|
paulo@0
|
299 int port;
|
paulo@0
|
300
|
paulo@0
|
301 port = gt_config_get_int ("main/port=6346");
|
paulo@0
|
302 setup_listening_port (port);
|
paulo@0
|
303
|
paulo@0
|
304 time (&start_time);
|
paulo@0
|
305
|
paulo@0
|
306 fw_test_timer = timer_add (FW_RETEST_INTERVAL, fw_test, NULL);
|
paulo@0
|
307 }
|
paulo@0
|
308
|
paulo@0
|
309 void gt_bind_cleanup (void)
|
paulo@0
|
310 {
|
paulo@0
|
311 save_fw_status ();
|
paulo@0
|
312
|
paulo@0
|
313 /* gt_node_free() will remove the listening input callback */
|
paulo@0
|
314 gt_node_free (GT_SELF);
|
paulo@0
|
315 GT_SELF = NULL;
|
paulo@0
|
316
|
paulo@0
|
317 start_time = 0;
|
paulo@0
|
318 last_connect = 0;
|
paulo@0
|
319
|
paulo@0
|
320 timer_remove_zero (&fw_test_timer);
|
paulo@0
|
321 }
|