Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/transfer/push_proxy.c Sat Feb 20 21:18:28 2010 -0800 1.3 @@ -0,0 +1,292 @@ 1.4 +/* 1.5 + * $Id: push_proxy.c,v 1.2 2004/06/02 07:13:02 hipnod Exp $ 1.6 + * 1.7 + * Copyright (C) 2004 giFT project (gift.sourceforge.net) 1.8 + * 1.9 + * This program is free software; you can redistribute it and/or modify it 1.10 + * under the terms of the GNU General Public License as published by the 1.11 + * Free Software Foundation; either version 2, or (at your option) any 1.12 + * later version. 1.13 + * 1.14 + * This program is distributed in the hope that it will be useful, but 1.15 + * WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + * General Public License for more details. 1.18 + */ 1.19 + 1.20 +#include "gt_gnutella.h" 1.21 + 1.22 +#include "gt_node.h" 1.23 +#include "gt_packet.h" /* htovs() */ 1.24 + 1.25 +#include "transfer/push_proxy.h" 1.26 + 1.27 +/*****************************************************************************/ 1.28 + 1.29 +/* 1.30 + * All this GGEP stuff will move somewhere else soon. Just haven't decided 1.31 + * where to put it. 1.32 + */ 1.33 + 1.34 +/*****************************************************************************/ 1.35 + 1.36 +#define PROXY_DEBUG gt_config_get_int("push_proxy/debug=0") 1.37 + 1.38 +/*****************************************************************************/ 1.39 + 1.40 +#define GGEP_HDR_LEN (1) /* 0xc3 */ 1.41 +#define GGEP_EXT_MAX_LEN (63) /* use only a single len chunk for now */ 1.42 + 1.43 +enum ggep_length_flags 1.44 +{ 1.45 + GGEP_LEN_NOT_LAST = 0x80, /* not the last chunk */ 1.46 + GGEP_LEN_LAST = 0x40, /* last length chunk flag */ 1.47 +}; 1.48 + 1.49 +enum ggep_extension_flags 1.50 +{ 1.51 + GGEP_EXTF_LAST = 0x80, /* last extension */ 1.52 + GGEP_EXTF_COBS_ENCODED = 0x40, /* encoded with COBS-encoding */ 1.53 + GGEP_EXTF_COMPRESSED = 0x20, /* compressed */ 1.54 + GGEP_EXTF_RESERVED = 0x10, /* reserved */ 1.55 + 1.56 + /* lower 4 bits is identifier length */ 1.57 +}; 1.58 + 1.59 +/*****************************************************************************/ 1.60 + 1.61 +struct proxy_addr 1.62 +{ 1.63 + in_addr_t ipv4; 1.64 + in_port_t port; 1.65 +}; 1.66 + 1.67 +typedef struct ggep 1.68 +{ 1.69 + uint8_t *block; 1.70 + size_t block_len; 1.71 + size_t offset; 1.72 + size_t last_ext_offset; 1.73 + BOOL error; 1.74 +} ggep_t; 1.75 + 1.76 +/*****************************************************************************/ 1.77 + 1.78 +static ggep_t proxy_block; 1.79 +static Dataset *proxies; 1.80 + 1.81 +/*****************************************************************************/ 1.82 + 1.83 +static BOOL ggep_grow (ggep_t *ggep, size_t sz) 1.84 +{ 1.85 + uint8_t *new_block; 1.86 + size_t new_size; 1.87 + 1.88 + new_size = ggep->block_len + sz; 1.89 + if (!(new_block = realloc (ggep->block, new_size))) 1.90 + return FALSE; 1.91 + 1.92 + ggep->block = new_block; 1.93 + ggep->block_len = new_size; 1.94 + 1.95 + return TRUE; 1.96 +} 1.97 + 1.98 +static BOOL ggep_init (ggep_t *ggep) 1.99 +{ 1.100 + ggep->block_len = 1; 1.101 + ggep->offset = 1; 1.102 + ggep->last_ext_offset = 0; 1.103 + ggep->error = FALSE; 1.104 + 1.105 + if (!(ggep->block = malloc (1))) 1.106 + return FALSE; 1.107 + 1.108 + /* append magic byte */ 1.109 + ggep->block[0] = 0xc3; 1.110 + 1.111 + return TRUE; 1.112 +} 1.113 + 1.114 +static void ggep_append (ggep_t *ggep, const void *data, size_t data_size) 1.115 +{ 1.116 + if (ggep_grow (ggep, data_size) == FALSE) 1.117 + { 1.118 + ggep->error = TRUE; 1.119 + return; 1.120 + } 1.121 + 1.122 + assert (ggep->offset + data_size <= ggep->block_len); 1.123 + memcpy (&ggep->block[ggep->offset], data, data_size); 1.124 + ggep->offset += data_size; 1.125 +} 1.126 + 1.127 +/* TODO: this should use a writev()-like interface */ 1.128 +static BOOL ggep_append_extension (ggep_t *ggep, const char *id, 1.129 + const uint8_t *data, size_t data_len) 1.130 +{ 1.131 + uint8_t id_len; 1.132 + uint8_t ext_flags; 1.133 + uint8_t ext_data_len; 1.134 + 1.135 + id_len = strlen (id) & 0x0f; 1.136 + 1.137 + /* disable Encoding, Compression, LastExtension bits, len in low 4 bits */ 1.138 + ext_flags = id_len; 1.139 + 1.140 + /* track position of last extension for setting LastExtension bit */ 1.141 + ggep->last_ext_offset = ggep->offset; 1.142 + 1.143 + /* extension flag header */ 1.144 + ggep_append (ggep, &ext_flags, 1); 1.145 + 1.146 + /* extension identifier */ 1.147 + ggep_append (ggep, id, id_len); 1.148 + 1.149 + assert (data_len <= GGEP_EXT_MAX_LEN); 1.150 + ext_data_len = data_len | GGEP_LEN_LAST; /* add last length chunk flag */ 1.151 + 1.152 + /* the extension length */ 1.153 + ggep_append (ggep, &ext_data_len, 1); 1.154 + 1.155 + /* the extension data */ 1.156 + ggep_append (ggep, data, data_len); 1.157 + 1.158 + if (ggep->error) 1.159 + return FALSE; 1.160 + 1.161 + return TRUE; 1.162 +} 1.163 + 1.164 +static BOOL ggep_seal (ggep_t *ggep) 1.165 +{ 1.166 + if (ggep->last_ext_offset == 0) 1.167 + return FALSE; 1.168 + 1.169 + /* set the LastExtension bit on the last extension */ 1.170 + ggep->block[ggep->last_ext_offset] |= GGEP_EXTF_LAST; 1.171 + return TRUE; 1.172 +} 1.173 + 1.174 +static void ggep_finish (ggep_t *ggep) 1.175 +{ 1.176 + free (ggep->block); 1.177 +} 1.178 + 1.179 +/*****************************************************************************/ 1.180 + 1.181 +static void ds_add_proxy (ds_data_t *key, ds_data_t *value, void **cmp) 1.182 +{ 1.183 + uint8_t *push_ext = cmp[0]; 1.184 + size_t *push_ext_len = cmp[1]; 1.185 + in_port_t port; 1.186 + struct proxy_addr *proxy = value->data; 1.187 + 1.188 + port = htovs (proxy->port); 1.189 + 1.190 + if (*push_ext_len + 6 >= GGEP_EXT_MAX_LEN) 1.191 + return; 1.192 + 1.193 + /* build the PUSH extension */ 1.194 + memcpy (&push_ext[*push_ext_len], &proxy->ipv4, 4); *push_ext_len += 4; 1.195 + memcpy (&push_ext[*push_ext_len], &port, 2); *push_ext_len += 2; 1.196 +} 1.197 + 1.198 +static void update_block (ggep_t *ggep) 1.199 +{ 1.200 + uint8_t push_ext[GGEP_EXT_MAX_LEN]; /* ugh */ 1.201 + size_t push_ext_len; /* double ugh */ 1.202 + void *cmp[2]; 1.203 + 1.204 + ggep_finish (ggep); 1.205 + 1.206 + if (ggep_init (ggep) == FALSE) 1.207 + return; 1.208 + 1.209 + cmp[0] = push_ext; 1.210 + cmp[1] = &push_ext_len; 1.211 + 1.212 + push_ext_len = 0; 1.213 + dataset_foreach (proxies, DS_FOREACH(ds_add_proxy), cmp); 1.214 + assert (push_ext_len <= GGEP_EXT_MAX_LEN); 1.215 + 1.216 + if (ggep_append_extension (ggep, "PUSH", push_ext, push_ext_len) == FALSE) 1.217 + return; 1.218 + 1.219 + ggep_seal (ggep); 1.220 +} 1.221 + 1.222 +/*****************************************************************************/ 1.223 + 1.224 +static void push_proxy_change (GtNode *node, in_addr_t ipv4, 1.225 + in_port_t port, BOOL add) 1.226 +{ 1.227 + struct proxy_addr addr; 1.228 + struct proxy_addr *stored; 1.229 + 1.230 + addr.ipv4 = ipv4; 1.231 + addr.port = port; 1.232 + 1.233 + stored = dataset_lookup (proxies, &node, sizeof(node)); 1.234 + if (PROXY_DEBUG) 1.235 + { 1.236 + if (add && !stored) 1.237 + GT->DBGFN (GT, "adding push proxy %s:%hu", net_ip_str (ipv4), port); 1.238 + else if (!add && stored) 1.239 + GT->DBGFN (GT, "rming push proxy %s:%hu", net_ip_str (ipv4), port); 1.240 + } 1.241 + 1.242 + if (add) 1.243 + dataset_insert (&proxies, &node, sizeof(node), &addr, sizeof(addr)); 1.244 + else 1.245 + dataset_remove (proxies, &node, sizeof(node)); 1.246 + 1.247 + update_block (&proxy_block); 1.248 +} 1.249 + 1.250 +void gt_push_proxy_add (GtNode *node, in_addr_t ipv4, in_port_t port) 1.251 +{ 1.252 + assert (node->push_proxy_ip == 0); 1.253 + assert (node->push_proxy_port == 0); 1.254 + 1.255 + push_proxy_change (node, ipv4, port, TRUE); 1.256 + node->push_proxy_ip = ipv4; 1.257 + node->push_proxy_port = port; 1.258 +} 1.259 + 1.260 +/* 1.261 + * This must be called if the port changes, or if the proxy disconnects. 1.262 + */ 1.263 +void gt_push_proxy_del (GtNode *node) 1.264 +{ 1.265 + push_proxy_change (node, node->push_proxy_ip, 1.266 + node->push_proxy_port, FALSE); 1.267 + node->push_proxy_ip = 0; 1.268 + node->push_proxy_port = 0; 1.269 +} 1.270 + 1.271 +BOOL gt_push_proxy_get_ggep_block (uint8_t **block, size_t *block_len) 1.272 +{ 1.273 + if (dataset_length (proxies) == 0) 1.274 + return FALSE; 1.275 + 1.276 + *block = proxy_block.block; 1.277 + *block_len = proxy_block.block_len; 1.278 + 1.279 + return TRUE; 1.280 +} 1.281 + 1.282 +/*****************************************************************************/ 1.283 + 1.284 +void gt_push_proxy_init (void) 1.285 +{ 1.286 + ggep_init (&proxy_block); 1.287 +} 1.288 + 1.289 +void gt_push_proxy_cleanup (void) 1.290 +{ 1.291 + dataset_clear (proxies); 1.292 + proxies = NULL; 1.293 + 1.294 + ggep_finish (&proxy_block); 1.295 +}