diff 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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/gt_bind.c	Sat Feb 20 21:18:28 2010 -0800
     1.3 @@ -0,0 +1,321 @@
     1.4 +/*
     1.5 + * $Id: gt_bind.c,v 1.6 2004/04/17 06:08:14 hipnod Exp $
     1.6 + *
     1.7 + * Copyright (C) 2001-2004 giFT project (gift.sourceforge.net)
     1.8 + *
     1.9 + * This program is free software; you can redistribute it and/or modify it
    1.10 + * under the terms of the GNU General Public License as published by the
    1.11 + * Free Software Foundation; either version 2, or (at your option) any
    1.12 + * later version.
    1.13 + *
    1.14 + * This program is distributed in the hope that it will be useful, but
    1.15 + * WITHOUT ANY WARRANTY; without even the implied warranty of
    1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.17 + * General Public License for more details.
    1.18 + */
    1.19 +
    1.20 +#include "gt_gnutella.h"
    1.21 +#include "gt_node.h"
    1.22 +#include "gt_node_list.h"
    1.23 +
    1.24 +#include "gt_accept.h"
    1.25 +#include "gt_bind.h"
    1.26 +#include "gt_packet.h"
    1.27 +#include "gt_share_state.h"
    1.28 +
    1.29 +#include "transfer/push_proxy.h"
    1.30 +
    1.31 +/*****************************************************************************/
    1.32 +
    1.33 +/* global node pointer for this machine */
    1.34 +GtNode *GT_SELF;
    1.35 +
    1.36 +/*****************************************************************************/
    1.37 +
    1.38 +/* how often to retest the firewalled status of this node */
    1.39 +#define FW_RETEST_INTERVAL                (60 * MINUTES)
    1.40 +
    1.41 +/* maximum amount of time before last connect read from disk before
    1.42 + * reassuming this node is firewalled on startup */
    1.43 +#define FW_MAX_RETEST_TIME                (7 * EDAYS)
    1.44 +
    1.45 +/*****************************************************************************/
    1.46 +
    1.47 +/* time at which this node started running */
    1.48 +static time_t     start_time;
    1.49 +
    1.50 +/* last time we got a connection on this host */
    1.51 +static time_t     last_connect;
    1.52 +
    1.53 +/* retest firewalled status every so often */
    1.54 +static timer_id   fw_test_timer;
    1.55 +
    1.56 +/*****************************************************************************/
    1.57 +
    1.58 +static char *fw_file (void)
    1.59 +{
    1.60 +	return gift_conf_path ("Gnutella/fwstatus");
    1.61 +}
    1.62 +
    1.63 +static void save_fw_status (void)
    1.64 +{
    1.65 +	FILE  *f;
    1.66 +
    1.67 +	if (!(f = fopen (fw_file (), "w")))
    1.68 +		return;
    1.69 +
    1.70 +	/*
    1.71 +	 * Store the last successful time of connect along with the port.
    1.72 +	 */
    1.73 +	fprintf (f, "%lu %hu\n", last_connect, GT_SELF->gt_port);
    1.74 +
    1.75 +	fclose (f);
    1.76 +}
    1.77 +
    1.78 +/* returns whether or not the node is firewalled */
    1.79 +static BOOL load_fw_status (in_port_t port)
    1.80 +{
    1.81 +	FILE      *f;
    1.82 +	char       buf[RW_BUFFER];
    1.83 +	time_t     last_time;
    1.84 +	in_port_t  last_port;
    1.85 +
    1.86 +	if (!(f = fopen (fw_file (), "r")))
    1.87 +		return TRUE;
    1.88 +
    1.89 +	if (fgets (buf, sizeof (buf) - 1, f) == NULL)
    1.90 +	{
    1.91 +		fclose (f);
    1.92 +		return TRUE;
    1.93 +	}
    1.94 +
    1.95 +	fclose (f);
    1.96 +
    1.97 +	/* Store the time of the last successful connect, so
    1.98 +	 * > 0 means _not_ firewalled */
    1.99 +	if (sscanf (buf, "%lu %hu", &last_time, &last_port) != 2)
   1.100 +		return TRUE;
   1.101 +
   1.102 +	/* if we got a connection within a recent time at some point with this
   1.103 +	 * port, mark not firewalled */
   1.104 +	if ((last_time > 0 && last_time < FW_MAX_RETEST_TIME) &&
   1.105 +	    last_port == port)
   1.106 +	{
   1.107 +		last_connect = last_time;
   1.108 +		return FALSE;
   1.109 +	}
   1.110 +
   1.111 +	return TRUE;
   1.112 +}
   1.113 +
   1.114 +static gt_node_class_t read_class (void)
   1.115 +{
   1.116 +	char *klass;
   1.117 +
   1.118 +	klass = gt_config_get_str ("main/class");
   1.119 +
   1.120 +	if (klass && strstr (klass, "ultra"))
   1.121 +		return GT_NODE_ULTRA;
   1.122 +
   1.123 +	return GT_NODE_LEAF;
   1.124 +}
   1.125 +
   1.126 +static void setup_self (GtNode *node, TCPC *c, in_port_t port)
   1.127 +{
   1.128 +	/* load the firewalled status of this port */
   1.129 +	node->firewalled = load_fw_status (port);
   1.130 +
   1.131 +	/* attach the connection to this node */
   1.132 +	gt_node_connect (node, c);
   1.133 +	node->gt_port = port;
   1.134 +
   1.135 +	/* load the class for this node */
   1.136 +	node->klass = read_class ();
   1.137 +
   1.138 +	input_add (c->fd, c, INPUT_READ,
   1.139 +	           (InputCallback)gnutella_handle_incoming, FALSE);
   1.140 +}
   1.141 +
   1.142 +static GtNode *bind_gnutella_port (in_port_t port)
   1.143 +{
   1.144 +	GtNode  *node;
   1.145 +	TCPC    *c;
   1.146 +
   1.147 +	GT->DBGFN (GT, "entered");
   1.148 +
   1.149 +	if (!(node = gt_node_new ()))
   1.150 +		return NULL;
   1.151 +
   1.152 +	/* assume sane defaults in case the bind fails */
   1.153 +	node->gt_port    = 0;
   1.154 +	node->firewalled = TRUE;
   1.155 +	node->klass      = GT_NODE_LEAF;
   1.156 +
   1.157 +	if (!port || !(c = tcp_bind (port, FALSE)))
   1.158 +	{
   1.159 +		GT->warn (GT, "Failed binding port %d, setting firewalled", port);
   1.160 +		return node;
   1.161 +	}
   1.162 +
   1.163 +	GT->dbg (GT, "bound to port %d", port);
   1.164 +
   1.165 +	/* setup what will become GT_SELF structure */
   1.166 +	setup_self (node, c, port);
   1.167 +
   1.168 +	return node;
   1.169 +}
   1.170 +
   1.171 +static void setup_listening_port (in_port_t port)
   1.172 +{
   1.173 +	GT_SELF = bind_gnutella_port (port);
   1.174 +
   1.175 +	/*
   1.176 +	 * If running in local mode, let the user set firewalled status in
   1.177 +	 * GNUTELLA_LOCAL_FW.  Not sure if this is a good idea, but it makes
   1.178 +	 * testing easier.
   1.179 +	 */
   1.180 +	if (GNUTELLA_LOCAL_MODE)
   1.181 +	{
   1.182 +		if (GNUTELLA_LOCAL_FW)
   1.183 +			GT_SELF->firewalled = TRUE;
   1.184 +		else
   1.185 +			GT_SELF->firewalled = FALSE;
   1.186 +	}
   1.187 +}
   1.188 +
   1.189 +/*****************************************************************************/
   1.190 +
   1.191 +BOOL gt_bind_is_firewalled (void)
   1.192 +{
   1.193 +	if (!GT_SELF->firewalled)
   1.194 +		return FALSE;
   1.195 +
   1.196 +	/*
   1.197 +	 * Pretend we are not firewalled at the beginning in order
   1.198 +	 * to possibly get more connections, to prove we are not firewalled.
   1.199 +	 */
   1.200 +	if (gt_uptime () < 10 * EMINUTES)
   1.201 +		return FALSE;
   1.202 +
   1.203 +	/* we are firewalled */
   1.204 +	return TRUE;
   1.205 +}
   1.206 +
   1.207 +void gt_bind_clear_firewalled (void)
   1.208 +{
   1.209 +	time (&last_connect);
   1.210 +	GT_SELF->firewalled = FALSE;
   1.211 +}
   1.212 +
   1.213 +static BOOL fwtest_node (GtNode *node)
   1.214 +{
   1.215 +	GtPacket *pkt;
   1.216 +	BOOL      ret;
   1.217 +
   1.218 +	if (!GT_SELF->firewalled)
   1.219 +		return FALSE;
   1.220 +
   1.221 +	if (!(pkt = gt_packet_vendor (GT_VMSG_TCP_CONNECT_BACK)))
   1.222 +		return FALSE;
   1.223 +
   1.224 +	gt_packet_put_port (pkt, GT_SELF->gt_port);
   1.225 +	GT->DBGSOCK (GT, GT_CONN(node), "fwtesting");
   1.226 +
   1.227 +	ret = gt_node_send_if_supported (node, pkt);
   1.228 +	gt_packet_free (pkt);
   1.229 +
   1.230 +	return ret;
   1.231 +}
   1.232 +
   1.233 +/*****************************************************************************/
   1.234 +
   1.235 +static void push_proxy_request (GtNode *node)
   1.236 +{
   1.237 +	GtPacket *pkt;
   1.238 +
   1.239 +	if (!(pkt = gt_packet_vendor (GT_VMSG_PUSH_PROXY_REQ)))
   1.240 +		return;
   1.241 +
   1.242 +	/* the GUID of the PushProxyRequest must be our client identifier */
   1.243 +	gt_packet_set_guid (pkt, GT_SELF_GUID);
   1.244 +
   1.245 +	gt_node_send_if_supported (node, pkt);
   1.246 +
   1.247 +	gt_packet_free (pkt);
   1.248 +}
   1.249 +
   1.250 +/*****************************************************************************/
   1.251 +
   1.252 +/*
   1.253 + * Called when a new connection to a node has completed.
   1.254 + */
   1.255 +void gt_bind_completed_connection (GtNode *node)
   1.256 +{
   1.257 +	if (node->vmsgs_sent && dataset_length (node->vmsgs_supported) > 0)
   1.258 +		return;
   1.259 +
   1.260 +	node->vmsgs_sent = TRUE;
   1.261 +
   1.262 +	fwtest_node (node);
   1.263 +	push_proxy_request (node);
   1.264 +}
   1.265 +
   1.266 +/*****************************************************************************/
   1.267 +
   1.268 +static GtNode *retest (TCPC *c, GtNode *node, void *udata)
   1.269 +{
   1.270 +	/*
   1.271 +	 * Only clear firewalled status once and if the node supports
   1.272 +	 * the TcpConnectBack message.
   1.273 +	 */
   1.274 +	if (fwtest_node (node) && GT_SELF->firewalled == FALSE)
   1.275 +	{
   1.276 +		GT->DBGFN (GT, "clearing firewalled status");
   1.277 +		GT_SELF->firewalled = TRUE;
   1.278 +	}
   1.279 +
   1.280 +	return NULL;
   1.281 +}
   1.282 +
   1.283 +static BOOL fw_test (void *udata)
   1.284 +{
   1.285 +	gt_conn_foreach (retest, NULL,
   1.286 +	                 GT_NODE_NONE, GT_NODE_CONNECTED, 0);
   1.287 +
   1.288 +	return TRUE;
   1.289 +}
   1.290 +
   1.291 +/*****************************************************************************/
   1.292 +
   1.293 +time_t gt_uptime (void)
   1.294 +{
   1.295 +	return start_time;
   1.296 +}
   1.297 +
   1.298 +/*****************************************************************************/
   1.299 +
   1.300 +void gt_bind_init (void)
   1.301 +{
   1.302 +	int port;
   1.303 +
   1.304 +	port = gt_config_get_int ("main/port=6346");
   1.305 +	setup_listening_port (port);
   1.306 +
   1.307 +	time (&start_time);
   1.308 +
   1.309 +	fw_test_timer = timer_add  (FW_RETEST_INTERVAL, fw_test, NULL);
   1.310 +}
   1.311 +
   1.312 +void gt_bind_cleanup (void)
   1.313 +{
   1.314 +	save_fw_status ();
   1.315 +
   1.316 +	/* gt_node_free() will remove the listening input callback */
   1.317 +	gt_node_free (GT_SELF);
   1.318 +	GT_SELF = NULL;
   1.319 +
   1.320 +	start_time   = 0;
   1.321 +	last_connect = 0;
   1.322 +
   1.323 +	timer_remove_zero (&fw_test_timer);
   1.324 +}