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