comparison src/gt_bind.c @ 0:d39e1d0d75b6

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