view 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 source
1 /*
2 * $Id: gt_message.c,v 1.6 2004/01/07 07:24:43 hipnod Exp $
3 *
4 * Copyright (C) 2001-2003 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 "msg_handler.h"
20 #include "gt_netorg.h"
21 #include "gt_connect.h"
23 #include "gt_utils.h"
25 #include "io/rx_stack.h" /* gt_rx_stack_new */
26 #include "io/tx_stack.h" /* gt_tx_stack_new */
28 #include "gt_message.h"
30 /*****************************************************************************/
32 extern void gt_vmsg_send_supported (GtNode *node); /* vendor.c */
34 /*****************************************************************************/
36 extern GT_MSG_HANDLER(gt_msg_ping);
37 extern GT_MSG_HANDLER(gt_msg_ping_reply);
38 extern GT_MSG_HANDLER(gt_msg_bye);
39 extern GT_MSG_HANDLER(gt_msg_push);
40 extern GT_MSG_HANDLER(gt_msg_query_route);
41 extern GT_MSG_HANDLER(gt_msg_query);
42 extern GT_MSG_HANDLER(gt_msg_query_reply);
43 extern GT_MSG_HANDLER(gt_msg_vendor);
45 static struct msg_handler
46 {
47 uint8_t command;
48 GtMessageHandler func;
49 }
50 msg_handler_table[] =
51 {
52 /* table listed not in numerical order, but by frequency of messages */
53 { GT_MSG_QUERY, gt_msg_query },
54 { GT_MSG_QUERY_REPLY, gt_msg_query_reply },
55 { GT_MSG_PING_REPLY, gt_msg_ping_reply },
56 { GT_MSG_PING, gt_msg_ping },
57 { GT_MSG_PUSH, gt_msg_push },
58 { GT_MSG_QUERY_ROUTE, gt_msg_query_route },
59 { GT_MSG_VENDOR, gt_msg_vendor },
60 { GT_MSG_VENDOR_STD, gt_msg_vendor }, /* same as non-standard */
61 { GT_MSG_BYE, gt_msg_bye },
62 { 0x00, NULL }
63 };
65 /*****************************************************************************/
67 static BOOL handle_message (TCPC *c, GtPacket *packet)
68 {
69 struct msg_handler *handler;
70 uint8_t command;
72 if (!packet)
73 return FALSE;
75 command = gt_packet_command (packet);
77 /* locate the handler */
78 for (handler = msg_handler_table; handler->func; handler++)
79 {
80 if (command == handler->command)
81 {
82 handler->func (GT_NODE(c), c, packet);
83 return TRUE;
84 }
85 }
87 GIFT_ERROR (("[%s] found no handler for cmd %hx, payload %hx",
88 net_ip_str (GT_NODE(c)->ip), command,
89 gt_packet_payload_len (packet)));
91 return FALSE;
92 }
94 static void cleanup_node_rx (GtNode *node)
95 {
96 TCPC *c = GT_CONN(node);
98 assert (GT_NODE(c) == node);
99 gt_node_disconnect (c);
100 }
102 /* TODO: make this the same type as cleanup_node_rx */
103 static void cleanup_node_tx (GtTxStack *stack, GtNode *node)
104 {
105 TCPC *c = GT_CONN(node);
107 assert (GT_NODE(c) == node);
108 gt_node_disconnect (c);
109 }
111 static void recv_packet (GtNode *node, GtPacket *packet)
112 {
113 assert (packet != NULL);
115 gt_packet_log (packet, GT_CONN(node), FALSE);
116 (void)handle_message (node->c, packet);
117 }
119 /* Find out what our IP is */
120 static in_addr_t get_self_ip (TCPC *c)
121 {
122 in_addr_t our_ip;
123 char *ip_str;
125 if ((ip_str = dataset_lookupstr (GT_NODE(c)->hdr, "remote-ip")))
126 {
127 /*
128 * Since we may be firewalled, we may not know what our ip is. So set
129 * the ip from what the other node thinks it is.
130 *
131 * Doing this allows you to setup port forwarding on a firewall
132 * and accept incoming connections.
133 */
134 our_ip = net_ip (ip_str);
135 }
136 else
137 {
138 struct sockaddr_in saddr;
139 int len = sizeof (saddr);
141 if (getsockname (c->fd, (struct sockaddr *)&saddr, &len) == 0)
142 our_ip = saddr.sin_addr.s_addr;
143 else
144 our_ip = net_ip ("127.0.0.1");
145 }
147 return our_ip;
148 }
150 /*
151 * Begin a node connection with the peer on the specified TCPC.
152 *
153 * We arrive here from either an incoming or outgoing connection.
154 * This is the entrance point to the main packet-reading loop.
155 *
156 * After setting up the connection, we send the node a ping.
157 * If it doesn't respond after a timeout, we will destroy the
158 * connection.
159 */
160 void gnutella_start_connection (int fd, input_id id, TCPC *c)
161 {
162 GtPacket *ping;
163 GtNode *node;
165 node = GT_NODE(c);
166 assert (GT_CONN(node) == c);
168 /* remove the old input handler first -- need to before sending data */
169 input_remove (id);
171 if (net_sock_error (c->fd))
172 {
173 if (HANDSHAKE_DEBUG)
174 gt_node_error (c, NULL);
176 gt_node_disconnect (c);
177 return;
178 }
180 /* if this is the crawler, disconnect */
181 if (dataset_lookupstr (GT_NODE(c)->hdr, "crawler"))
182 {
183 if (HANDSHAKE_DEBUG)
184 GT->DBGSOCK (GT, c, "closing crawler connection");
186 gt_node_disconnect (c);
187 return;
188 }
190 if (!(node->rx_stack = gt_rx_stack_new (node, c, node->rx_inflated)))
191 {
192 if (HANDSHAKE_DEBUG)
193 GT->DBGSOCK (GT, c, "error allocating rx_stack");
195 gt_node_disconnect (c);
196 return;
197 }
199 if (!(node->tx_stack = gt_tx_stack_new (c, node->tx_deflated)))
200 {
201 if (HANDSHAKE_DEBUG)
202 GT->DBGSOCK (GT, c, "error allocating tx stack");
204 gt_node_disconnect (c);
205 return;
206 }
208 /* determine the other node's opinion of our IP address */
209 node->my_ip = get_self_ip (c);
211 /* determine the other ends port */
212 peer_addr (c->fd, NULL, &node->peer_port);
214 if (HANDSHAKE_DEBUG)
215 {
216 GT->DBGSOCK (GT, c, "self IP=[%s]", net_ip_str (node->my_ip));
217 GT->DBGSOCK (GT, c, "peer port=%hu", node->peer_port);
218 }
220 if (!(ping = gt_packet_new (GT_MSG_PING, 1, NULL)))
221 {
222 gt_node_disconnect (c);
223 return;
224 }
226 /* set the state as intermediately connecting and mark the node connected
227 * only when it replies to our ping */
228 gt_node_state_set (node, GT_NODE_CONNECTING_2);
230 /* give the connection some more time */
231 gnutella_set_handshake_timeout (c, TIMEOUT_3 * SECONDS);
233 /*
234 * Setup our packet handlers, for both receiving and sending packets.
235 */
236 gt_rx_stack_set_handler (node->rx_stack,
237 (GtRxStackHandler)recv_packet,
238 (GtRxStackCleanup)cleanup_node_rx,
239 node);
241 gt_tx_stack_set_handler (node->tx_stack,
242 (GtTxStackCleanup)cleanup_node_tx,
243 node);
245 /* send first ping */
246 gt_packet_send (c, ping);
247 gt_packet_free (ping);
249 /* send MessagesSupported Vendor message, if this node supports it */
250 gt_vmsg_send_supported (node);
251 }