diff src/message/gt_message.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/message/gt_message.c	Sat Feb 20 21:18:28 2010 -0800
     1.3 @@ -0,0 +1,251 @@
     1.4 +/*
     1.5 + * $Id: gt_message.c,v 1.6 2004/01/07 07:24:43 hipnod Exp $
     1.6 + *
     1.7 + * Copyright (C) 2001-2003 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 "msg_handler.h"
    1.22 +
    1.23 +#include "gt_netorg.h"
    1.24 +#include "gt_connect.h"
    1.25 +
    1.26 +#include "gt_utils.h"
    1.27 +
    1.28 +#include "io/rx_stack.h"               /* gt_rx_stack_new */
    1.29 +#include "io/tx_stack.h"               /* gt_tx_stack_new */
    1.30 +
    1.31 +#include "gt_message.h"
    1.32 +
    1.33 +/*****************************************************************************/
    1.34 +
    1.35 +extern void gt_vmsg_send_supported (GtNode *node);   /* vendor.c */
    1.36 +
    1.37 +/*****************************************************************************/
    1.38 +
    1.39 +extern GT_MSG_HANDLER(gt_msg_ping);
    1.40 +extern GT_MSG_HANDLER(gt_msg_ping_reply);
    1.41 +extern GT_MSG_HANDLER(gt_msg_bye);
    1.42 +extern GT_MSG_HANDLER(gt_msg_push);
    1.43 +extern GT_MSG_HANDLER(gt_msg_query_route);
    1.44 +extern GT_MSG_HANDLER(gt_msg_query);
    1.45 +extern GT_MSG_HANDLER(gt_msg_query_reply);
    1.46 +extern GT_MSG_HANDLER(gt_msg_vendor);
    1.47 +
    1.48 +static struct msg_handler
    1.49 +{
    1.50 +	uint8_t command;
    1.51 +	GtMessageHandler func;
    1.52 +}
    1.53 +msg_handler_table[] =
    1.54 +{
    1.55 +	/* table listed not in numerical order, but by frequency of messages */
    1.56 +	{ GT_MSG_QUERY,        gt_msg_query       },
    1.57 +	{ GT_MSG_QUERY_REPLY,  gt_msg_query_reply },
    1.58 +	{ GT_MSG_PING_REPLY,   gt_msg_ping_reply  },
    1.59 +	{ GT_MSG_PING,         gt_msg_ping        },
    1.60 +	{ GT_MSG_PUSH,         gt_msg_push        },
    1.61 +	{ GT_MSG_QUERY_ROUTE,  gt_msg_query_route },
    1.62 +	{ GT_MSG_VENDOR,       gt_msg_vendor      },
    1.63 +	{ GT_MSG_VENDOR_STD,   gt_msg_vendor      }, /* same as non-standard */
    1.64 +	{ GT_MSG_BYE,          gt_msg_bye         },
    1.65 +	{ 0x00,                NULL               }
    1.66 +};
    1.67 +
    1.68 +/*****************************************************************************/
    1.69 +
    1.70 +static BOOL handle_message (TCPC *c, GtPacket *packet)
    1.71 +{
    1.72 +	struct msg_handler *handler;
    1.73 +	uint8_t command;
    1.74 +
    1.75 +	if (!packet)
    1.76 +		return FALSE;
    1.77 +
    1.78 +	command = gt_packet_command (packet);
    1.79 +
    1.80 +	/* locate the handler */
    1.81 +	for (handler = msg_handler_table; handler->func; handler++)
    1.82 +	{
    1.83 +		if (command == handler->command)
    1.84 +		{
    1.85 +			handler->func (GT_NODE(c), c, packet);
    1.86 +			return TRUE;
    1.87 +		}
    1.88 +	}
    1.89 +
    1.90 +	GIFT_ERROR (("[%s] found no handler for cmd %hx, payload %hx",
    1.91 +				 net_ip_str (GT_NODE(c)->ip), command,
    1.92 +				 gt_packet_payload_len (packet)));
    1.93 +
    1.94 +	return FALSE;
    1.95 +}
    1.96 +
    1.97 +static void cleanup_node_rx (GtNode *node)
    1.98 +{
    1.99 +	TCPC    *c = GT_CONN(node);
   1.100 +
   1.101 +	assert (GT_NODE(c) == node);
   1.102 +	gt_node_disconnect (c);
   1.103 +}
   1.104 +
   1.105 +/* TODO: make this the same type as cleanup_node_rx */
   1.106 +static void cleanup_node_tx (GtTxStack *stack, GtNode *node)
   1.107 +{
   1.108 +	TCPC *c = GT_CONN(node);
   1.109 +
   1.110 +	assert (GT_NODE(c) == node);
   1.111 +	gt_node_disconnect (c);
   1.112 +}
   1.113 +
   1.114 +static void recv_packet (GtNode *node, GtPacket *packet)
   1.115 +{
   1.116 +	assert (packet != NULL);
   1.117 +
   1.118 +	gt_packet_log (packet, GT_CONN(node), FALSE);
   1.119 +	(void)handle_message (node->c, packet);
   1.120 +}
   1.121 +
   1.122 +/* Find out what our IP is */
   1.123 +static in_addr_t get_self_ip (TCPC *c)
   1.124 +{
   1.125 +	in_addr_t our_ip;
   1.126 +	char     *ip_str;
   1.127 +
   1.128 +	if ((ip_str = dataset_lookupstr (GT_NODE(c)->hdr, "remote-ip")))
   1.129 +	{
   1.130 +		/*
   1.131 +		 * Since we may be firewalled, we may not know what our ip is.  So set
   1.132 +		 * the ip from what the other node thinks it is.
   1.133 +		 *
   1.134 +		 * Doing this allows you to setup port forwarding on a firewall
   1.135 +		 * and accept incoming connections.
   1.136 +		 */
   1.137 +		our_ip = net_ip (ip_str);
   1.138 +	}
   1.139 +	else
   1.140 +	{
   1.141 +		struct sockaddr_in saddr;
   1.142 +		int    len = sizeof (saddr);
   1.143 +
   1.144 +		if (getsockname (c->fd, (struct sockaddr *)&saddr, &len) == 0)
   1.145 +			our_ip = saddr.sin_addr.s_addr;
   1.146 +		else
   1.147 +			our_ip = net_ip ("127.0.0.1");
   1.148 +	}
   1.149 +
   1.150 +	return our_ip;
   1.151 +}
   1.152 +
   1.153 +/*
   1.154 + * Begin a node connection with the peer on the specified TCPC.
   1.155 + *
   1.156 + * We arrive here from either an incoming or outgoing connection.
   1.157 + * This is the entrance point to the main packet-reading loop.
   1.158 + *
   1.159 + * After setting up the connection, we send the node a ping.
   1.160 + * If it doesn't respond after a timeout, we will destroy the
   1.161 + * connection.
   1.162 + */
   1.163 +void gnutella_start_connection (int fd, input_id id, TCPC *c)
   1.164 +{
   1.165 +	GtPacket    *ping;
   1.166 +	GtNode      *node;
   1.167 +
   1.168 +	node = GT_NODE(c);
   1.169 +	assert (GT_CONN(node) == c);
   1.170 +
   1.171 +	/* remove the old input handler first -- need to before sending data */
   1.172 +	input_remove (id);
   1.173 +
   1.174 +	if (net_sock_error (c->fd))
   1.175 +	{
   1.176 +		if (HANDSHAKE_DEBUG)
   1.177 +			gt_node_error (c, NULL);
   1.178 +
   1.179 +		gt_node_disconnect (c);
   1.180 +		return;
   1.181 +	}
   1.182 +
   1.183 +	/* if this is the crawler, disconnect */
   1.184 +	if (dataset_lookupstr (GT_NODE(c)->hdr, "crawler"))
   1.185 +	{
   1.186 +		if (HANDSHAKE_DEBUG)
   1.187 +			GT->DBGSOCK (GT, c, "closing crawler connection");
   1.188 +
   1.189 +		gt_node_disconnect (c);
   1.190 +		return;
   1.191 +	}
   1.192 +
   1.193 +	if (!(node->rx_stack = gt_rx_stack_new (node, c, node->rx_inflated)))
   1.194 +	{
   1.195 +		if (HANDSHAKE_DEBUG)
   1.196 +			GT->DBGSOCK (GT, c, "error allocating rx_stack");
   1.197 +
   1.198 +		gt_node_disconnect (c);
   1.199 +		return;
   1.200 +	}
   1.201 +
   1.202 +	if (!(node->tx_stack = gt_tx_stack_new (c, node->tx_deflated)))
   1.203 +	{
   1.204 +		if (HANDSHAKE_DEBUG)
   1.205 +			GT->DBGSOCK (GT, c, "error allocating tx stack");
   1.206 +
   1.207 +		gt_node_disconnect (c);
   1.208 +		return;
   1.209 +	}
   1.210 +
   1.211 +	/* determine the other node's opinion of our IP address */
   1.212 +	node->my_ip = get_self_ip (c);
   1.213 +
   1.214 +	/* determine the other ends port */
   1.215 +	peer_addr (c->fd, NULL, &node->peer_port);
   1.216 +
   1.217 +	if (HANDSHAKE_DEBUG)
   1.218 +	{
   1.219 +		GT->DBGSOCK (GT, c, "self IP=[%s]", net_ip_str (node->my_ip));
   1.220 +		GT->DBGSOCK (GT, c, "peer port=%hu", node->peer_port);
   1.221 +	}
   1.222 +
   1.223 +	if (!(ping = gt_packet_new (GT_MSG_PING, 1, NULL)))
   1.224 +	{
   1.225 +		gt_node_disconnect (c);
   1.226 +		return;
   1.227 +	}
   1.228 +
   1.229 +	/* set the state as intermediately connecting and mark the node connected
   1.230 +	 * only when it replies to our ping */
   1.231 +	gt_node_state_set (node, GT_NODE_CONNECTING_2);
   1.232 +
   1.233 +	/* give the connection some more time */
   1.234 +	gnutella_set_handshake_timeout (c, TIMEOUT_3 * SECONDS);
   1.235 +
   1.236 +	/*
   1.237 +	 * Setup our packet handlers, for both receiving and sending packets.
   1.238 +	 */
   1.239 +	gt_rx_stack_set_handler (node->rx_stack,
   1.240 +	                         (GtRxStackHandler)recv_packet,
   1.241 +	                         (GtRxStackCleanup)cleanup_node_rx,
   1.242 +	                         node);
   1.243 +
   1.244 +	gt_tx_stack_set_handler (node->tx_stack,
   1.245 +	                         (GtTxStackCleanup)cleanup_node_tx,
   1.246 +	                         node);
   1.247 +
   1.248 +	/* send first ping */
   1.249 +	gt_packet_send (c, ping);
   1.250 +	gt_packet_free (ping);
   1.251 +
   1.252 +	/* send MessagesSupported Vendor message, if this node supports it */
   1.253 +	gt_vmsg_send_supported (node);
   1.254 +}