view 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
line source
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 */
17 #include "gt_gnutella.h"
18 #include "gt_node.h"
19 #include "gt_node_list.h"
21 #include "gt_accept.h"
22 #include "gt_bind.h"
23 #include "gt_packet.h"
24 #include "gt_share_state.h"
26 #include "transfer/push_proxy.h"
28 /*****************************************************************************/
30 /* global node pointer for this machine */
31 GtNode *GT_SELF;
33 /*****************************************************************************/
35 /* how often to retest the firewalled status of this node */
36 #define FW_RETEST_INTERVAL (60 * MINUTES)
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)
42 /*****************************************************************************/
44 /* time at which this node started running */
45 static time_t start_time;
47 /* last time we got a connection on this host */
48 static time_t last_connect;
50 /* retest firewalled status every so often */
51 static timer_id fw_test_timer;
53 /*****************************************************************************/
55 static char *fw_file (void)
56 {
57 return gift_conf_path ("Gnutella/fwstatus");
58 }
60 static void save_fw_status (void)
61 {
62 FILE *f;
64 if (!(f = fopen (fw_file (), "w")))
65 return;
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);
72 fclose (f);
73 }
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;
83 if (!(f = fopen (fw_file (), "r")))
84 return TRUE;
86 if (fgets (buf, sizeof (buf) - 1, f) == NULL)
87 {
88 fclose (f);
89 return TRUE;
90 }
92 fclose (f);
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;
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 }
108 return TRUE;
109 }
111 static gt_node_class_t read_class (void)
112 {
113 char *klass;
115 klass = gt_config_get_str ("main/class");
117 if (klass && strstr (klass, "ultra"))
118 return GT_NODE_ULTRA;
120 return GT_NODE_LEAF;
121 }
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);
128 /* attach the connection to this node */
129 gt_node_connect (node, c);
130 node->gt_port = port;
132 /* load the class for this node */
133 node->klass = read_class ();
135 input_add (c->fd, c, INPUT_READ,
136 (InputCallback)gnutella_handle_incoming, FALSE);
137 }
139 static GtNode *bind_gnutella_port (in_port_t port)
140 {
141 GtNode *node;
142 TCPC *c;
144 GT->DBGFN (GT, "entered");
146 if (!(node = gt_node_new ()))
147 return NULL;
149 /* assume sane defaults in case the bind fails */
150 node->gt_port = 0;
151 node->firewalled = TRUE;
152 node->klass = GT_NODE_LEAF;
154 if (!port || !(c = tcp_bind (port, FALSE)))
155 {
156 GT->warn (GT, "Failed binding port %d, setting firewalled", port);
157 return node;
158 }
160 GT->dbg (GT, "bound to port %d", port);
162 /* setup what will become GT_SELF structure */
163 setup_self (node, c, port);
165 return node;
166 }
168 static void setup_listening_port (in_port_t port)
169 {
170 GT_SELF = bind_gnutella_port (port);
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 }
186 /*****************************************************************************/
188 BOOL gt_bind_is_firewalled (void)
189 {
190 if (!GT_SELF->firewalled)
191 return FALSE;
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;
200 /* we are firewalled */
201 return TRUE;
202 }
204 void gt_bind_clear_firewalled (void)
205 {
206 time (&last_connect);
207 GT_SELF->firewalled = FALSE;
208 }
210 static BOOL fwtest_node (GtNode *node)
211 {
212 GtPacket *pkt;
213 BOOL ret;
215 if (!GT_SELF->firewalled)
216 return FALSE;
218 if (!(pkt = gt_packet_vendor (GT_VMSG_TCP_CONNECT_BACK)))
219 return FALSE;
221 gt_packet_put_port (pkt, GT_SELF->gt_port);
222 GT->DBGSOCK (GT, GT_CONN(node), "fwtesting");
224 ret = gt_node_send_if_supported (node, pkt);
225 gt_packet_free (pkt);
227 return ret;
228 }
230 /*****************************************************************************/
232 static void push_proxy_request (GtNode *node)
233 {
234 GtPacket *pkt;
236 if (!(pkt = gt_packet_vendor (GT_VMSG_PUSH_PROXY_REQ)))
237 return;
239 /* the GUID of the PushProxyRequest must be our client identifier */
240 gt_packet_set_guid (pkt, GT_SELF_GUID);
242 gt_node_send_if_supported (node, pkt);
244 gt_packet_free (pkt);
245 }
247 /*****************************************************************************/
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;
257 node->vmsgs_sent = TRUE;
259 fwtest_node (node);
260 push_proxy_request (node);
261 }
263 /*****************************************************************************/
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 }
277 return NULL;
278 }
280 static BOOL fw_test (void *udata)
281 {
282 gt_conn_foreach (retest, NULL,
283 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
285 return TRUE;
286 }
288 /*****************************************************************************/
290 time_t gt_uptime (void)
291 {
292 return start_time;
293 }
295 /*****************************************************************************/
297 void gt_bind_init (void)
298 {
299 int port;
301 port = gt_config_get_int ("main/port=6346");
302 setup_listening_port (port);
304 time (&start_time);
306 fw_test_timer = timer_add (FW_RETEST_INTERVAL, fw_test, NULL);
307 }
309 void gt_bind_cleanup (void)
310 {
311 save_fw_status ();
313 /* gt_node_free() will remove the listening input callback */
314 gt_node_free (GT_SELF);
315 GT_SELF = NULL;
317 start_time = 0;
318 last_connect = 0;
320 timer_remove_zero (&fw_test_timer);
321 }