2
* $Id: vmsg.c,v 1.20 2004/01/14 20:52:33 rmanfredi Exp $
4
* Copyright (c) 2003, Raphael Manfredi
6
* Vendor-specific messages.
8
*----------------------------------------------------------------------
9
* This file is part of gtk-gnutella.
11
* gtk-gnutella is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License as published by
13
* the Free Software Foundation; either version 2 of the License, or
14
* (at your option) any later version.
16
* gtk-gnutella is distributed in the hope that it will be useful,
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
* GNU General Public License for more details.
21
* You should have received a copy of the GNU General Public License
22
* along with gtk-gnutella; if not, write to the Free Software
24
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
*----------------------------------------------------------------------
28
#include "common.h" /* For -DUSE_DMALLOC */
34
#include "routing.h" /* For message_set_muid() */
35
#include "gnet_stats.h"
36
#include "settings.h" /* For listen_ip() */
37
#include "override.h" /* Must be the last header included */
39
RCSID("$Id: vmsg.c,v 1.20 2004/01/14 20:52:33 rmanfredi Exp $");
41
static gchar v_tmp[256];
44
* Vendor message handler.
49
typedef void (*vmsg_handler_t)(struct gnutella_node *n,
50
struct vmsg *vmsg, gchar *payload, gint size);
53
* Definition of vendor messages
59
vmsg_handler_t handler;
63
static void handle_messages_supported(struct gnutella_node *n,
64
struct vmsg *vmsg, gchar *payload, gint size);
65
static void handle_hops_flow(struct gnutella_node *n,
66
struct vmsg *vmsg, gchar *payload, gint size);
67
static void handle_connect_back(struct gnutella_node *n,
68
struct vmsg *vmsg, gchar *payload, gint size);
69
static void handle_proxy_req(struct gnutella_node *n,
70
struct vmsg *vmsg, gchar *payload, gint size);
71
static void handle_proxy_ack(struct gnutella_node *n,
72
struct vmsg *vmsg, gchar *payload, gint size);
75
* Known vendor-specific messages.
77
static struct vmsg vmsg_map[] = {
78
/* This list MUST be sorted by vendor, id, version */
80
{ T_0000, 0x0000, 0x0000, handle_messages_supported, "Messages Supported" },
81
{ T_BEAR, 0x0004, 0x0001, handle_hops_flow, "Hops Flow" },
82
{ T_BEAR, 0x0007, 0x0001, handle_connect_back, "Connect Back" },
83
{ T_LIME, 0x0015, 0x0002, handle_proxy_req, "Push Proxy Request" },
84
{ T_LIME, 0x0016, 0x0002, handle_proxy_ack, "Push Proxy Acknowledgment" },
86
/* Above line intentionally left blank (for "!}sort" on vi) */
89
#define END(v) (v - 1 + sizeof(v) / sizeof(v[0]))
92
* Items in the "Message Supported" vector.
100
#define VMS_ITEM_SIZE 8 /* Each entry is 8 bytes (4+2+2) */
105
* Find message, given vendor code, and id, version.
107
* We don't necessarily match the version exactly: we only guarantee to
108
* return a handler whose version number is greater or equal than the message
111
* Returns handler callback if found, NULL otherwise.
113
static struct vmsg *find_message(
114
guint32 vendor, guint16 id, guint16 version)
116
struct vmsg *low = vmsg_map;
117
struct vmsg *high = END(vmsg_map);
119
while (low <= high) {
120
struct vmsg *mid = low + (high - low) / 2;
123
c = vendor_code_cmp(mid->vendor, vendor);
127
c = mid->id < id ? -1 : +1;
131
if (mid->version < version) /* Return match if >= */
143
return NULL; /* Not found */
149
* Main entry point to handle reception of vendor-specific message.
151
void vmsg_handle(struct gnutella_node *n)
153
struct gnutella_vendor *v = (struct gnutella_vendor *) n->data;
159
READ_GUINT32_BE(v->vendor, vendor);
160
READ_GUINT16_LE(v->selector_id, id);
161
READ_GUINT16_LE(v->version, version);
163
vm = find_message(vendor, id, version);
166
printf("VMSG %s \"%s\": vendor=%s, id=%u, version=%u\n",
167
gmsg_infostr(&n->header), vm == NULL ? "UNKNOWN" : vm->name,
168
vendor_code_str(vendor), id, version);
171
* If we can't handle the message, we count it as "unknown type", which
172
* is not completely exact because the type (vendor-specific) is known,
173
* it was only the subtype of that message which was unknown. Still, I
174
* don't think it is ambiguous enough to warrant another drop type.
179
gnet_stats_count_dropped(n, MSG_DROP_UNKNOWN_TYPE);
181
g_warning("unknown vendor message: %s vendor=%s id=%u version=%u",
182
gmsg_infostr(&n->header), vendor_code_str(vendor), id, version);
186
(*vm->handler)(n, vm, n->data + sizeof(*v), n->size - sizeof(*v));
192
* Fill common message header part for all vendor-specific messages.
193
* The GUID is blanked (all zero bytes), TTL is set to 1 and hops to 0.
194
* Those common values can be superseded by the caller if needed.
196
* `size' is only the size of the payload we filled so far.
197
* `maxsize' is the size of the already allocated vendor messsage.
199
* Returns the total size of the whole Gnutella message.
201
static guint32 vmsg_fill_header(struct gnutella_header *header,
202
guint32 size, guint32 maxsize)
206
memset(header->muid, 0, 16); /* Default GUID: all blank */
207
header->function = GTA_MSG_VENDOR;
211
msize = size + sizeof(struct gnutella_vendor);
213
WRITE_GUINT32_LE(msize, header->size);
215
msize += sizeof(struct gnutella_header);
218
g_error("allocated vendor message is only %u bytes, would need %u",
227
* Fill leading part of the payload data, containing the common part for
228
* all vendor-specific messages.
230
* Returns start of payload after that common part.
232
static guchar *vmsg_fill_type(
233
struct gnutella_vendor *base, guint32 vendor, guint16 id, guint16 version)
235
WRITE_GUINT32_BE(vendor, base->vendor);
236
WRITE_GUINT16_LE(id, base->selector_id);
237
WRITE_GUINT16_LE(version, base->version);
239
return (guchar *) (base + 1);
243
* handle_messages_supported
245
* Handle the "Messages Supported" message.
247
static void handle_messages_supported(struct gnutella_node *n,
248
struct vmsg *vmsg, gchar *payload, gint size)
252
READ_GUINT16_LE(payload, count);
255
printf("VMSG node %s <%s> supports %u vendor message%s\n",
256
node_ip(n), node_vendor(n), count,
257
count == 1 ? "" : "s");
259
if (size != sizeof(count) + count * VMS_ITEM_SIZE) {
260
g_warning("bad payload length in \"Messages Supported\" from %s <%s>: "
261
"expected %d bytes in vector for %d item%s, got %d",
262
node_ip(n), node_vendor(n),
263
count * VMS_ITEM_SIZE, count, count == 1 ? "" : "s",
264
size - (gint) sizeof(count));
268
/* XXX -- we don't need this support yet -- RAM, 30/01/2003 */
270
g_warning("handle_messages_supported() not implemented yet!");
274
* vmsg_send_messages_supported
276
* Send a "Messages Supported" message to specified node, telling it which
277
* subset of the vendor messages we can understand. We don't send information
278
* about the "Messages Supported" message itself, since this one is guarateeed
279
* to be always understood
281
void vmsg_send_messages_supported(struct gnutella_node *n)
283
struct gnutella_msg_vendor *m = (struct gnutella_msg_vendor *) v_tmp;
284
guint16 count = G_N_ELEMENTS(vmsg_map) - 1;
285
guint32 paysize = sizeof(count) + count * VMS_ITEM_SIZE;
290
msgsize = vmsg_fill_header(&m->header, paysize, sizeof(v_tmp));
291
payload = vmsg_fill_type(&m->data, T_0000, 0, 0);
294
* First 2 bytes is the number of entries in the vector.
297
WRITE_GUINT16_LE(count, payload);
301
* Fill one entry per message type supported, excepted ourselves.
304
for (i = 0; i < G_N_ELEMENTS(vmsg_map); i++) {
305
struct vmsg *msg = &vmsg_map[i];
307
if (msg->vendor == T_0000) /* Don't send info about ourselves */
310
WRITE_GUINT32_BE(msg->vendor, payload);
312
WRITE_GUINT16_LE(msg->id, payload);
314
WRITE_GUINT16_LE(msg->version, payload);
318
gmsg_sendto_one(n, (gchar *) m, msgsize);
324
* Handle the "Hops Flow" message.
326
static void handle_hops_flow(struct gnutella_node *n,
327
struct vmsg *vmsg, gchar *payload, gint size)
331
g_assert(vmsg->version <= 1);
334
g_warning("got improper %s (payload has %d bytes) from %s <%s>",
335
vmsg->name, size, node_ip(n), node_vendor(n));
340
node_set_hops_flow(n, hops);
344
* vmsg_send_hops_flow
346
* Send an "Hops Flow" message to specified node.
348
void vmsg_send_hops_flow(struct gnutella_node *n, guint8 hops)
350
struct gnutella_msg_vendor *m = (struct gnutella_msg_vendor *) v_tmp;
351
guint32 paysize = sizeof(hops);
355
msgsize = vmsg_fill_header(&m->header, paysize, sizeof(v_tmp));
356
payload = vmsg_fill_type(&m->data, T_BEAR, 4, 1);
361
* Send the message as a control message, so that it gets sent ASAP.
364
gmsg_ctrl_sendto_one(n, (gchar *) m, msgsize);
368
* handle_connect_back
370
* Handle the "Connect Back" message.
372
static void handle_connect_back(struct gnutella_node *n,
373
struct vmsg *vmsg, gchar *payload, gint size)
377
g_assert(vmsg->version <= 1);
380
g_warning("got improper %s (payload has %d byte%ss) "
381
"from %s <%s>", vmsg->name, size, size == 1 ? "" : "s",
382
node_ip(n), node_vendor(n));
386
READ_GUINT16_LE(payload, port);
389
g_warning("got improper port #%d in %s from %s <%s>",
390
port, vmsg->name, node_ip(n), node_vendor(n));
394
node_connect_back(n, port);
398
* vmsg_send_connect_back
400
* Send an "Connect Back" message to specified node, telling it to connect
401
* back to us on the specified port.
403
void vmsg_send_connect_back(struct gnutella_node *n, guint16 port)
405
struct gnutella_msg_vendor *m = (struct gnutella_msg_vendor *) v_tmp;
406
guint32 paysize = sizeof(port);
410
msgsize = vmsg_fill_header(&m->header, paysize, sizeof(v_tmp));
411
payload = vmsg_fill_type(&m->data, T_BEAR, 7, 1);
413
WRITE_GUINT16_LE(port, payload);
415
gmsg_sendto_one(n, (gchar *) m, msgsize);
421
* Handle reception of the "Push Proxy Request" message.
423
static void handle_proxy_req(struct gnutella_node *n,
424
struct vmsg *vmsg, gchar *payload, gint size)
427
g_warning("got improper %s (payload has %d byte%ss) "
428
"from %s <%s>", vmsg->name, size, size == 1 ? "" : "s",
429
node_ip(n), node_vendor(n));
434
* Normally, a firewalled host should be a leaf node, not an UP.
435
* Warn if node is not a leaf, but accept to be the push proxy
439
if (!NODE_IS_LEAF(n))
440
g_warning("got %s from non-leaf node %s <%s>",
441
vmsg->name, node_ip(n), node_vendor(n));
444
* Add proxying info for this node. On successful completion,
445
* we'll send an acknowledgement.
448
if (node_proxying_add(n, n->header.muid)) /* MUID is the node's GUID */
449
vmsg_send_proxy_ack(n, n->header.muid);
453
* vmsg_send_proxy_req
455
* Send a "Push Proxy Request" message to specified node, using supplied
456
* `muid' as the message ID (which is our GUID).
458
void vmsg_send_proxy_req(struct gnutella_node *n, gchar *muid)
460
struct gnutella_msg_vendor *m = (struct gnutella_msg_vendor *) v_tmp;
463
g_assert(!NODE_IS_LEAF(n));
465
msgsize = vmsg_fill_header(&m->header, 0, sizeof(v_tmp));
466
memcpy(m->header.muid, muid, 16);
467
(void) vmsg_fill_type(&m->data, T_LIME, 21, 2);
469
gmsg_sendto_one(n, (gchar *) m, msgsize);
472
g_warning("sent proxy REQ to %s <%s>", node_ip(n), node_vendor(n));
478
* Handle reception of the "Push Proxy Acknowledgment" message.
480
static void handle_proxy_ack(struct gnutella_node *n,
481
struct vmsg *vmsg, gchar *payload, gint size)
486
g_assert(vmsg->version >= 2);
489
g_warning("got improper %s (payload has %d byte%ss) "
490
"from %s <%s>", vmsg->name, size, size == 1 ? "" : "s",
491
node_ip(n), node_vendor(n));
495
READ_GUINT32_BE(payload, ip);
497
READ_GUINT16_LE(payload, port);
500
g_warning("got proxy ACK from %s <%s>: proxy at %s",
501
node_ip(n), node_vendor(n), ip_port_to_gchar(ip, port));
504
if (!host_is_valid(ip, port)) {
505
g_warning("got improper address %s in %s from %s <%s>",
506
ip_port_to_gchar(ip, port), vmsg->name,
507
node_ip(n), node_vendor(n));
511
node_proxy_add(n, ip, port);
515
* vmsg_send_proxy_ack
517
* Send a "Push Proxy Acknowledgment" message to specified node, using
518
* supplied `muid' as the message ID (which is the target node's GUID).
520
void vmsg_send_proxy_ack(struct gnutella_node *n, gchar *muid)
522
struct gnutella_msg_vendor *m = (struct gnutella_msg_vendor *) v_tmp;
523
guint32 paysize = sizeof(guint32) + sizeof(guint16);
527
msgsize = vmsg_fill_header(&m->header, paysize, sizeof(v_tmp));
528
memcpy(m->header.muid, muid, 16);
529
payload = vmsg_fill_type(&m->data, T_LIME, 22, 2);
531
WRITE_GUINT32_BE(listen_ip(), payload);
533
WRITE_GUINT16_LE(listen_port, payload);
536
* Reply with a control message, so that the issuer knows that we can
537
* proxyfy pushes to it ASAP.
540
gmsg_ctrl_sendto_one(n, (gchar *) m, msgsize);