paulo@0: /* paulo@0: * $Id: vendor.c,v 1.6 2004/03/26 11:44:13 hipnod Exp $ paulo@0: * paulo@0: * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) paulo@0: * paulo@0: * This program is free software; you can redistribute it and/or modify it paulo@0: * under the terms of the GNU General Public License as published by the paulo@0: * Free Software Foundation; either version 2, or (at your option) any paulo@0: * later version. paulo@0: * paulo@0: * This program is distributed in the hope that it will be useful, but paulo@0: * WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU paulo@0: * General Public License for more details. paulo@0: */ paulo@0: paulo@0: #include "gt_gnutella.h" paulo@0: #include "message/msg_handler.h" paulo@0: paulo@0: #include "gt_connect.h" /* gt_connect_test */ paulo@0: #include "gt_bind.h" paulo@0: paulo@0: #include "gt_utils.h" /* make_str */ paulo@0: paulo@0: #include "transfer/push_proxy.h" paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: #define EMPTY_VENDOR { 0, 0, 0, 0 } paulo@0: paulo@0: #define vmsg_name(name) \ paulo@0: name##_struct paulo@0: paulo@0: #define declare_vmsg(name,vendor,id) \ paulo@0: const struct gt_vendor_msg vmsg_name(name) = { vendor, id }; \ paulo@0: const struct gt_vendor_msg *name = &name##_struct; paulo@0: paulo@0: /* Globally visible vendor message structs */ paulo@0: declare_vmsg(GT_VMSG_MESSAGES_SUPP, EMPTY_VENDOR, 0); paulo@0: declare_vmsg(GT_VMSG_HOPS_FLOW, "BEAR", 4); paulo@0: declare_vmsg(GT_VMSG_TCP_CONNECT_BACK, "BEAR", 7); paulo@0: declare_vmsg(GT_VMSG_PUSH_PROXY_REQ, "LIME", 21); paulo@0: declare_vmsg(GT_VMSG_PUSH_PROXY_ACK, "LIME", 22); paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static GT_MSG_HANDLER(gt_msg_messages_supported); paulo@0: static GT_MSG_HANDLER(gt_msg_hops_flow); paulo@0: static GT_MSG_HANDLER(gt_msg_tcp_connect_back); paulo@0: static GT_MSG_HANDLER(gt_msg_push_proxy_request); paulo@0: static GT_MSG_HANDLER(gt_msg_push_proxy_acknowledgement); paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: struct gt_vendor_table paulo@0: { paulo@0: const struct gt_vendor_msg *msg; paulo@0: GtMessageHandler func; paulo@0: uint16_t version; paulo@0: BOOL in_msgs_supported; /* inside MessagesSupported */ paulo@0: }; paulo@0: paulo@0: static struct gt_vendor_table vendor_table[] = paulo@0: { paulo@0: { &vmsg_name(GT_VMSG_MESSAGES_SUPP), gt_msg_messages_supported, paulo@0: 1, FALSE }, paulo@0: { &vmsg_name(GT_VMSG_HOPS_FLOW), gt_msg_hops_flow, paulo@0: 1, FALSE /*TODO: support receving*/ }, paulo@0: { &vmsg_name(GT_VMSG_TCP_CONNECT_BACK), gt_msg_tcp_connect_back, paulo@0: 1, TRUE }, paulo@0: { &vmsg_name(GT_VMSG_PUSH_PROXY_REQ), gt_msg_push_proxy_request, paulo@0: 2, TRUE }, paulo@0: { &vmsg_name(GT_VMSG_PUSH_PROXY_ACK), gt_msg_push_proxy_acknowledgement, paulo@0: 2, FALSE }, paulo@0: }; paulo@0: paulo@0: static const size_t nr_vmsgs = sizeof(vendor_table) / sizeof(vendor_table[0]); paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static void vmsg_init (struct gt_vendor_msg *msg, paulo@0: unsigned char *vendor_id, uint16_t id) paulo@0: { paulo@0: /* initialize to zero because of potential structure alignment issues */ paulo@0: memset (msg, 0, sizeof(struct gt_vendor_msg)); paulo@0: paulo@0: memcpy (&msg->vendor_id, vendor_id, 4); paulo@0: msg->id = id; paulo@0: } paulo@0: paulo@0: static void append_vmsg (GtPacket *pkt, const struct gt_vendor_msg *msg, paulo@0: uint16_t ver) paulo@0: { paulo@0: gt_packet_put_ustr (pkt, msg->vendor_id, 4); paulo@0: gt_packet_put_uint16 (pkt, msg->id); paulo@0: gt_packet_put_uint16 (pkt, ver); paulo@0: } paulo@0: paulo@0: void gt_vmsg_send_supported (GtNode *node) paulo@0: { paulo@0: GtPacket *pkt; paulo@0: int i; paulo@0: uint16_t vector_len = 0; paulo@0: paulo@0: if (!dataset_lookupstr (node->hdr, "vendor-message")) paulo@0: return; paulo@0: paulo@0: if (!(pkt = gt_packet_vendor (GT_VMSG_MESSAGES_SUPP))) paulo@0: return; paulo@0: paulo@0: gt_packet_put_uint16 (pkt, 0); paulo@0: paulo@0: for (i = 0; i < nr_vmsgs; i++) paulo@0: { paulo@0: if (vendor_table[i].in_msgs_supported) paulo@0: { paulo@0: vector_len++; paulo@0: append_vmsg (pkt, vendor_table[i].msg, vendor_table[i].version); paulo@0: } paulo@0: } paulo@0: paulo@0: /* XXX: packet put_xxx functions don't work with gt_packet_seek :( */ paulo@0: vector_len = htovl (vector_len); paulo@0: memcpy (&pkt->data[GNUTELLA_HDR_LEN + VMSG_HDR_LEN], &vector_len, 2); paulo@0: paulo@0: if (gt_packet_error (pkt)) paulo@0: { paulo@0: gt_packet_free (pkt); paulo@0: return; paulo@0: } paulo@0: paulo@0: GT->DBGSOCK (GT, GT_CONN(node), "sending MessagesSupported"); paulo@0: paulo@0: gt_packet_send (GT_CONN(node), pkt); paulo@0: gt_packet_free (pkt); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: GT_MSG_HANDLER(gt_msg_vendor) paulo@0: { paulo@0: struct gt_vendor_msg vmsg; paulo@0: unsigned char *vendor; paulo@0: int i; paulo@0: uint16_t id; paulo@0: uint16_t version; paulo@0: paulo@0: if (gt_packet_hops (packet) != 0 && gt_packet_ttl (packet) != 1) paulo@0: return; paulo@0: paulo@0: vendor = gt_packet_get_ustr (packet, 4); paulo@0: id = gt_packet_get_uint16 (packet); paulo@0: version = gt_packet_get_uint16 (packet); paulo@0: paulo@0: /* initialize a copy for making a single call to memcmp */ paulo@0: vmsg_init (&vmsg, vendor, id); paulo@0: paulo@0: if (gt_packet_error (packet)) paulo@0: { paulo@0: if (MSG_DEBUG) paulo@0: GT->DBGSOCK (GT, c, "Error parsing vendor message"); paulo@0: paulo@0: return; paulo@0: } paulo@0: paulo@0: for (i = 0; i < nr_vmsgs; i++) paulo@0: { paulo@0: if (memcmp (vendor_table[i].msg, &vmsg, sizeof(vmsg)) == 0 && paulo@0: version <= vendor_table[i].version) paulo@0: { paulo@0: vendor_table[i].func (MSG_HANDLER_ARG_NAMES); paulo@0: return; paulo@0: } paulo@0: } paulo@0: paulo@0: if (MSG_DEBUG) paulo@0: { paulo@0: GT->DBGSOCK (GT, c, "No handler for vendor message %s/%dv%d", paulo@0: make_str (vendor, 4), id, version); paulo@0: } paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static struct gt_vendor_table *find_in_vmsg_table (gt_vendor_msg_t *vmsg) paulo@0: { paulo@0: int i; paulo@0: paulo@0: for (i = 0; i < nr_vmsgs; i++) paulo@0: { paulo@0: if (memcmp (vendor_table[i].msg, vmsg, sizeof(*vmsg)) == 0) paulo@0: return &vendor_table[i]; paulo@0: } paulo@0: paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: static GT_MSG_HANDLER(gt_msg_messages_supported) paulo@0: { paulo@0: gt_vendor_msg_t vmsg; paulo@0: unsigned char *vendor_id; paulo@0: int i; paulo@0: uint16_t id; paulo@0: uint16_t version; paulo@0: uint16_t vector_len; paulo@0: paulo@0: vector_len = gt_packet_get_uint16 (packet); paulo@0: paulo@0: if (gt_packet_error (packet)) paulo@0: return; paulo@0: paulo@0: /* paulo@0: * Track the supported messages in a dataset on this node. paulo@0: */ paulo@0: for (i = 0; i < vector_len; i++) paulo@0: { paulo@0: struct gt_vendor_table *entry; paulo@0: paulo@0: vendor_id = gt_packet_get_ustr (packet, 4); paulo@0: id = gt_packet_get_uint16 (packet); paulo@0: version = gt_packet_get_uint16 (packet); paulo@0: paulo@0: if (gt_packet_error (packet)) paulo@0: break; paulo@0: paulo@0: vmsg_init (&vmsg, vendor_id, id); paulo@0: paulo@0: if (!(entry = find_in_vmsg_table (&vmsg))) paulo@0: continue; paulo@0: paulo@0: /* only send the minimum supported by both ends to this node */ paulo@0: version = MIN (version, entry->version); paulo@0: paulo@0: /* track support for this vendor message */ paulo@0: dataset_insert (&node->vmsgs_supported, &vmsg, sizeof(vmsg), paulo@0: &version, sizeof(version)); paulo@0: } paulo@0: paulo@0: /* send our batch of vendor messages now */ paulo@0: gt_bind_completed_connection (node); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static GT_MSG_HANDLER(gt_msg_hops_flow) paulo@0: { paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static GT_MSG_HANDLER(gt_msg_tcp_connect_back) paulo@0: { paulo@0: in_port_t port; paulo@0: paulo@0: port = gt_packet_get_port (packet); paulo@0: paulo@0: if (!port) paulo@0: return; paulo@0: paulo@0: gt_connect_test (node, port); paulo@0: } paulo@0: paulo@0: /*****************************************************************************/ paulo@0: paulo@0: static GT_MSG_HANDLER(gt_msg_push_proxy_request) paulo@0: { paulo@0: return; paulo@0: } paulo@0: paulo@0: static GT_MSG_HANDLER(gt_msg_push_proxy_acknowledgement) paulo@0: { paulo@0: in_addr_t ip; paulo@0: in_port_t port; paulo@0: paulo@0: ip = gt_packet_get_ip (packet); paulo@0: port = gt_packet_get_port (packet); paulo@0: paulo@0: if (gt_packet_error (packet)) paulo@0: return; paulo@0: paulo@0: gt_push_proxy_del (node); paulo@0: gt_push_proxy_add (node, ip, port); paulo@0: }