annotate 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
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 }