annotate src/transfer/push_proxy.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: push_proxy.c,v 1.2 2004/06/02 07:13:02 hipnod Exp $
paulo@0 3 *
paulo@0 4 * Copyright (C) 2004 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
paulo@0 19 #include "gt_node.h"
paulo@0 20 #include "gt_packet.h" /* htovs() */
paulo@0 21
paulo@0 22 #include "transfer/push_proxy.h"
paulo@0 23
paulo@0 24 /*****************************************************************************/
paulo@0 25
paulo@0 26 /*
paulo@0 27 * All this GGEP stuff will move somewhere else soon. Just haven't decided
paulo@0 28 * where to put it.
paulo@0 29 */
paulo@0 30
paulo@0 31 /*****************************************************************************/
paulo@0 32
paulo@0 33 #define PROXY_DEBUG gt_config_get_int("push_proxy/debug=0")
paulo@0 34
paulo@0 35 /*****************************************************************************/
paulo@0 36
paulo@0 37 #define GGEP_HDR_LEN (1) /* 0xc3 */
paulo@0 38 #define GGEP_EXT_MAX_LEN (63) /* use only a single len chunk for now */
paulo@0 39
paulo@0 40 enum ggep_length_flags
paulo@0 41 {
paulo@0 42 GGEP_LEN_NOT_LAST = 0x80, /* not the last chunk */
paulo@0 43 GGEP_LEN_LAST = 0x40, /* last length chunk flag */
paulo@0 44 };
paulo@0 45
paulo@0 46 enum ggep_extension_flags
paulo@0 47 {
paulo@0 48 GGEP_EXTF_LAST = 0x80, /* last extension */
paulo@0 49 GGEP_EXTF_COBS_ENCODED = 0x40, /* encoded with COBS-encoding */
paulo@0 50 GGEP_EXTF_COMPRESSED = 0x20, /* compressed */
paulo@0 51 GGEP_EXTF_RESERVED = 0x10, /* reserved */
paulo@0 52
paulo@0 53 /* lower 4 bits is identifier length */
paulo@0 54 };
paulo@0 55
paulo@0 56 /*****************************************************************************/
paulo@0 57
paulo@0 58 struct proxy_addr
paulo@0 59 {
paulo@0 60 in_addr_t ipv4;
paulo@0 61 in_port_t port;
paulo@0 62 };
paulo@0 63
paulo@0 64 typedef struct ggep
paulo@0 65 {
paulo@0 66 uint8_t *block;
paulo@0 67 size_t block_len;
paulo@0 68 size_t offset;
paulo@0 69 size_t last_ext_offset;
paulo@0 70 BOOL error;
paulo@0 71 } ggep_t;
paulo@0 72
paulo@0 73 /*****************************************************************************/
paulo@0 74
paulo@0 75 static ggep_t proxy_block;
paulo@0 76 static Dataset *proxies;
paulo@0 77
paulo@0 78 /*****************************************************************************/
paulo@0 79
paulo@0 80 static BOOL ggep_grow (ggep_t *ggep, size_t sz)
paulo@0 81 {
paulo@0 82 uint8_t *new_block;
paulo@0 83 size_t new_size;
paulo@0 84
paulo@0 85 new_size = ggep->block_len + sz;
paulo@0 86 if (!(new_block = realloc (ggep->block, new_size)))
paulo@0 87 return FALSE;
paulo@0 88
paulo@0 89 ggep->block = new_block;
paulo@0 90 ggep->block_len = new_size;
paulo@0 91
paulo@0 92 return TRUE;
paulo@0 93 }
paulo@0 94
paulo@0 95 static BOOL ggep_init (ggep_t *ggep)
paulo@0 96 {
paulo@0 97 ggep->block_len = 1;
paulo@0 98 ggep->offset = 1;
paulo@0 99 ggep->last_ext_offset = 0;
paulo@0 100 ggep->error = FALSE;
paulo@0 101
paulo@0 102 if (!(ggep->block = malloc (1)))
paulo@0 103 return FALSE;
paulo@0 104
paulo@0 105 /* append magic byte */
paulo@0 106 ggep->block[0] = 0xc3;
paulo@0 107
paulo@0 108 return TRUE;
paulo@0 109 }
paulo@0 110
paulo@0 111 static void ggep_append (ggep_t *ggep, const void *data, size_t data_size)
paulo@0 112 {
paulo@0 113 if (ggep_grow (ggep, data_size) == FALSE)
paulo@0 114 {
paulo@0 115 ggep->error = TRUE;
paulo@0 116 return;
paulo@0 117 }
paulo@0 118
paulo@0 119 assert (ggep->offset + data_size <= ggep->block_len);
paulo@0 120 memcpy (&ggep->block[ggep->offset], data, data_size);
paulo@0 121 ggep->offset += data_size;
paulo@0 122 }
paulo@0 123
paulo@0 124 /* TODO: this should use a writev()-like interface */
paulo@0 125 static BOOL ggep_append_extension (ggep_t *ggep, const char *id,
paulo@0 126 const uint8_t *data, size_t data_len)
paulo@0 127 {
paulo@0 128 uint8_t id_len;
paulo@0 129 uint8_t ext_flags;
paulo@0 130 uint8_t ext_data_len;
paulo@0 131
paulo@0 132 id_len = strlen (id) & 0x0f;
paulo@0 133
paulo@0 134 /* disable Encoding, Compression, LastExtension bits, len in low 4 bits */
paulo@0 135 ext_flags = id_len;
paulo@0 136
paulo@0 137 /* track position of last extension for setting LastExtension bit */
paulo@0 138 ggep->last_ext_offset = ggep->offset;
paulo@0 139
paulo@0 140 /* extension flag header */
paulo@0 141 ggep_append (ggep, &ext_flags, 1);
paulo@0 142
paulo@0 143 /* extension identifier */
paulo@0 144 ggep_append (ggep, id, id_len);
paulo@0 145
paulo@0 146 assert (data_len <= GGEP_EXT_MAX_LEN);
paulo@0 147 ext_data_len = data_len | GGEP_LEN_LAST; /* add last length chunk flag */
paulo@0 148
paulo@0 149 /* the extension length */
paulo@0 150 ggep_append (ggep, &ext_data_len, 1);
paulo@0 151
paulo@0 152 /* the extension data */
paulo@0 153 ggep_append (ggep, data, data_len);
paulo@0 154
paulo@0 155 if (ggep->error)
paulo@0 156 return FALSE;
paulo@0 157
paulo@0 158 return TRUE;
paulo@0 159 }
paulo@0 160
paulo@0 161 static BOOL ggep_seal (ggep_t *ggep)
paulo@0 162 {
paulo@0 163 if (ggep->last_ext_offset == 0)
paulo@0 164 return FALSE;
paulo@0 165
paulo@0 166 /* set the LastExtension bit on the last extension */
paulo@0 167 ggep->block[ggep->last_ext_offset] |= GGEP_EXTF_LAST;
paulo@0 168 return TRUE;
paulo@0 169 }
paulo@0 170
paulo@0 171 static void ggep_finish (ggep_t *ggep)
paulo@0 172 {
paulo@0 173 free (ggep->block);
paulo@0 174 }
paulo@0 175
paulo@0 176 /*****************************************************************************/
paulo@0 177
paulo@0 178 static void ds_add_proxy (ds_data_t *key, ds_data_t *value, void **cmp)
paulo@0 179 {
paulo@0 180 uint8_t *push_ext = cmp[0];
paulo@0 181 size_t *push_ext_len = cmp[1];
paulo@0 182 in_port_t port;
paulo@0 183 struct proxy_addr *proxy = value->data;
paulo@0 184
paulo@0 185 port = htovs (proxy->port);
paulo@0 186
paulo@0 187 if (*push_ext_len + 6 >= GGEP_EXT_MAX_LEN)
paulo@0 188 return;
paulo@0 189
paulo@0 190 /* build the PUSH extension */
paulo@0 191 memcpy (&push_ext[*push_ext_len], &proxy->ipv4, 4); *push_ext_len += 4;
paulo@0 192 memcpy (&push_ext[*push_ext_len], &port, 2); *push_ext_len += 2;
paulo@0 193 }
paulo@0 194
paulo@0 195 static void update_block (ggep_t *ggep)
paulo@0 196 {
paulo@0 197 uint8_t push_ext[GGEP_EXT_MAX_LEN]; /* ugh */
paulo@0 198 size_t push_ext_len; /* double ugh */
paulo@0 199 void *cmp[2];
paulo@0 200
paulo@0 201 ggep_finish (ggep);
paulo@0 202
paulo@0 203 if (ggep_init (ggep) == FALSE)
paulo@0 204 return;
paulo@0 205
paulo@0 206 cmp[0] = push_ext;
paulo@0 207 cmp[1] = &push_ext_len;
paulo@0 208
paulo@0 209 push_ext_len = 0;
paulo@0 210 dataset_foreach (proxies, DS_FOREACH(ds_add_proxy), cmp);
paulo@0 211 assert (push_ext_len <= GGEP_EXT_MAX_LEN);
paulo@0 212
paulo@0 213 if (ggep_append_extension (ggep, "PUSH", push_ext, push_ext_len) == FALSE)
paulo@0 214 return;
paulo@0 215
paulo@0 216 ggep_seal (ggep);
paulo@0 217 }
paulo@0 218
paulo@0 219 /*****************************************************************************/
paulo@0 220
paulo@0 221 static void push_proxy_change (GtNode *node, in_addr_t ipv4,
paulo@0 222 in_port_t port, BOOL add)
paulo@0 223 {
paulo@0 224 struct proxy_addr addr;
paulo@0 225 struct proxy_addr *stored;
paulo@0 226
paulo@0 227 addr.ipv4 = ipv4;
paulo@0 228 addr.port = port;
paulo@0 229
paulo@0 230 stored = dataset_lookup (proxies, &node, sizeof(node));
paulo@0 231 if (PROXY_DEBUG)
paulo@0 232 {
paulo@0 233 if (add && !stored)
paulo@0 234 GT->DBGFN (GT, "adding push proxy %s:%hu", net_ip_str (ipv4), port);
paulo@0 235 else if (!add && stored)
paulo@0 236 GT->DBGFN (GT, "rming push proxy %s:%hu", net_ip_str (ipv4), port);
paulo@0 237 }
paulo@0 238
paulo@0 239 if (add)
paulo@0 240 dataset_insert (&proxies, &node, sizeof(node), &addr, sizeof(addr));
paulo@0 241 else
paulo@0 242 dataset_remove (proxies, &node, sizeof(node));
paulo@0 243
paulo@0 244 update_block (&proxy_block);
paulo@0 245 }
paulo@0 246
paulo@0 247 void gt_push_proxy_add (GtNode *node, in_addr_t ipv4, in_port_t port)
paulo@0 248 {
paulo@0 249 assert (node->push_proxy_ip == 0);
paulo@0 250 assert (node->push_proxy_port == 0);
paulo@0 251
paulo@0 252 push_proxy_change (node, ipv4, port, TRUE);
paulo@0 253 node->push_proxy_ip = ipv4;
paulo@0 254 node->push_proxy_port = port;
paulo@0 255 }
paulo@0 256
paulo@0 257 /*
paulo@0 258 * This must be called if the port changes, or if the proxy disconnects.
paulo@0 259 */
paulo@0 260 void gt_push_proxy_del (GtNode *node)
paulo@0 261 {
paulo@0 262 push_proxy_change (node, node->push_proxy_ip,
paulo@0 263 node->push_proxy_port, FALSE);
paulo@0 264 node->push_proxy_ip = 0;
paulo@0 265 node->push_proxy_port = 0;
paulo@0 266 }
paulo@0 267
paulo@0 268 BOOL gt_push_proxy_get_ggep_block (uint8_t **block, size_t *block_len)
paulo@0 269 {
paulo@0 270 if (dataset_length (proxies) == 0)
paulo@0 271 return FALSE;
paulo@0 272
paulo@0 273 *block = proxy_block.block;
paulo@0 274 *block_len = proxy_block.block_len;
paulo@0 275
paulo@0 276 return TRUE;
paulo@0 277 }
paulo@0 278
paulo@0 279 /*****************************************************************************/
paulo@0 280
paulo@0 281 void gt_push_proxy_init (void)
paulo@0 282 {
paulo@0 283 ggep_init (&proxy_block);
paulo@0 284 }
paulo@0 285
paulo@0 286 void gt_push_proxy_cleanup (void)
paulo@0 287 {
paulo@0 288 dataset_clear (proxies);
paulo@0 289 proxies = NULL;
paulo@0 290
paulo@0 291 ggep_finish (&proxy_block);
paulo@0 292 }