view 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 source
1 /*
2 * $Id: push_proxy.c,v 1.2 2004/06/02 07:13:02 hipnod Exp $
3 *
4 * Copyright (C) 2004 giFT project (gift.sourceforge.net)
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 */
17 #include "gt_gnutella.h"
19 #include "gt_node.h"
20 #include "gt_packet.h" /* htovs() */
22 #include "transfer/push_proxy.h"
24 /*****************************************************************************/
26 /*
27 * All this GGEP stuff will move somewhere else soon. Just haven't decided
28 * where to put it.
29 */
31 /*****************************************************************************/
33 #define PROXY_DEBUG gt_config_get_int("push_proxy/debug=0")
35 /*****************************************************************************/
37 #define GGEP_HDR_LEN (1) /* 0xc3 */
38 #define GGEP_EXT_MAX_LEN (63) /* use only a single len chunk for now */
40 enum ggep_length_flags
41 {
42 GGEP_LEN_NOT_LAST = 0x80, /* not the last chunk */
43 GGEP_LEN_LAST = 0x40, /* last length chunk flag */
44 };
46 enum ggep_extension_flags
47 {
48 GGEP_EXTF_LAST = 0x80, /* last extension */
49 GGEP_EXTF_COBS_ENCODED = 0x40, /* encoded with COBS-encoding */
50 GGEP_EXTF_COMPRESSED = 0x20, /* compressed */
51 GGEP_EXTF_RESERVED = 0x10, /* reserved */
53 /* lower 4 bits is identifier length */
54 };
56 /*****************************************************************************/
58 struct proxy_addr
59 {
60 in_addr_t ipv4;
61 in_port_t port;
62 };
64 typedef struct ggep
65 {
66 uint8_t *block;
67 size_t block_len;
68 size_t offset;
69 size_t last_ext_offset;
70 BOOL error;
71 } ggep_t;
73 /*****************************************************************************/
75 static ggep_t proxy_block;
76 static Dataset *proxies;
78 /*****************************************************************************/
80 static BOOL ggep_grow (ggep_t *ggep, size_t sz)
81 {
82 uint8_t *new_block;
83 size_t new_size;
85 new_size = ggep->block_len + sz;
86 if (!(new_block = realloc (ggep->block, new_size)))
87 return FALSE;
89 ggep->block = new_block;
90 ggep->block_len = new_size;
92 return TRUE;
93 }
95 static BOOL ggep_init (ggep_t *ggep)
96 {
97 ggep->block_len = 1;
98 ggep->offset = 1;
99 ggep->last_ext_offset = 0;
100 ggep->error = FALSE;
102 if (!(ggep->block = malloc (1)))
103 return FALSE;
105 /* append magic byte */
106 ggep->block[0] = 0xc3;
108 return TRUE;
109 }
111 static void ggep_append (ggep_t *ggep, const void *data, size_t data_size)
112 {
113 if (ggep_grow (ggep, data_size) == FALSE)
114 {
115 ggep->error = TRUE;
116 return;
117 }
119 assert (ggep->offset + data_size <= ggep->block_len);
120 memcpy (&ggep->block[ggep->offset], data, data_size);
121 ggep->offset += data_size;
122 }
124 /* TODO: this should use a writev()-like interface */
125 static BOOL ggep_append_extension (ggep_t *ggep, const char *id,
126 const uint8_t *data, size_t data_len)
127 {
128 uint8_t id_len;
129 uint8_t ext_flags;
130 uint8_t ext_data_len;
132 id_len = strlen (id) & 0x0f;
134 /* disable Encoding, Compression, LastExtension bits, len in low 4 bits */
135 ext_flags = id_len;
137 /* track position of last extension for setting LastExtension bit */
138 ggep->last_ext_offset = ggep->offset;
140 /* extension flag header */
141 ggep_append (ggep, &ext_flags, 1);
143 /* extension identifier */
144 ggep_append (ggep, id, id_len);
146 assert (data_len <= GGEP_EXT_MAX_LEN);
147 ext_data_len = data_len | GGEP_LEN_LAST; /* add last length chunk flag */
149 /* the extension length */
150 ggep_append (ggep, &ext_data_len, 1);
152 /* the extension data */
153 ggep_append (ggep, data, data_len);
155 if (ggep->error)
156 return FALSE;
158 return TRUE;
159 }
161 static BOOL ggep_seal (ggep_t *ggep)
162 {
163 if (ggep->last_ext_offset == 0)
164 return FALSE;
166 /* set the LastExtension bit on the last extension */
167 ggep->block[ggep->last_ext_offset] |= GGEP_EXTF_LAST;
168 return TRUE;
169 }
171 static void ggep_finish (ggep_t *ggep)
172 {
173 free (ggep->block);
174 }
176 /*****************************************************************************/
178 static void ds_add_proxy (ds_data_t *key, ds_data_t *value, void **cmp)
179 {
180 uint8_t *push_ext = cmp[0];
181 size_t *push_ext_len = cmp[1];
182 in_port_t port;
183 struct proxy_addr *proxy = value->data;
185 port = htovs (proxy->port);
187 if (*push_ext_len + 6 >= GGEP_EXT_MAX_LEN)
188 return;
190 /* build the PUSH extension */
191 memcpy (&push_ext[*push_ext_len], &proxy->ipv4, 4); *push_ext_len += 4;
192 memcpy (&push_ext[*push_ext_len], &port, 2); *push_ext_len += 2;
193 }
195 static void update_block (ggep_t *ggep)
196 {
197 uint8_t push_ext[GGEP_EXT_MAX_LEN]; /* ugh */
198 size_t push_ext_len; /* double ugh */
199 void *cmp[2];
201 ggep_finish (ggep);
203 if (ggep_init (ggep) == FALSE)
204 return;
206 cmp[0] = push_ext;
207 cmp[1] = &push_ext_len;
209 push_ext_len = 0;
210 dataset_foreach (proxies, DS_FOREACH(ds_add_proxy), cmp);
211 assert (push_ext_len <= GGEP_EXT_MAX_LEN);
213 if (ggep_append_extension (ggep, "PUSH", push_ext, push_ext_len) == FALSE)
214 return;
216 ggep_seal (ggep);
217 }
219 /*****************************************************************************/
221 static void push_proxy_change (GtNode *node, in_addr_t ipv4,
222 in_port_t port, BOOL add)
223 {
224 struct proxy_addr addr;
225 struct proxy_addr *stored;
227 addr.ipv4 = ipv4;
228 addr.port = port;
230 stored = dataset_lookup (proxies, &node, sizeof(node));
231 if (PROXY_DEBUG)
232 {
233 if (add && !stored)
234 GT->DBGFN (GT, "adding push proxy %s:%hu", net_ip_str (ipv4), port);
235 else if (!add && stored)
236 GT->DBGFN (GT, "rming push proxy %s:%hu", net_ip_str (ipv4), port);
237 }
239 if (add)
240 dataset_insert (&proxies, &node, sizeof(node), &addr, sizeof(addr));
241 else
242 dataset_remove (proxies, &node, sizeof(node));
244 update_block (&proxy_block);
245 }
247 void gt_push_proxy_add (GtNode *node, in_addr_t ipv4, in_port_t port)
248 {
249 assert (node->push_proxy_ip == 0);
250 assert (node->push_proxy_port == 0);
252 push_proxy_change (node, ipv4, port, TRUE);
253 node->push_proxy_ip = ipv4;
254 node->push_proxy_port = port;
255 }
257 /*
258 * This must be called if the port changes, or if the proxy disconnects.
259 */
260 void gt_push_proxy_del (GtNode *node)
261 {
262 push_proxy_change (node, node->push_proxy_ip,
263 node->push_proxy_port, FALSE);
264 node->push_proxy_ip = 0;
265 node->push_proxy_port = 0;
266 }
268 BOOL gt_push_proxy_get_ggep_block (uint8_t **block, size_t *block_len)
269 {
270 if (dataset_length (proxies) == 0)
271 return FALSE;
273 *block = proxy_block.block;
274 *block_len = proxy_block.block_len;
276 return TRUE;
277 }
279 /*****************************************************************************/
281 void gt_push_proxy_init (void)
282 {
283 ggep_init (&proxy_block);
284 }
286 void gt_push_proxy_cleanup (void)
287 {
288 dataset_clear (proxies);
289 proxies = NULL;
291 ggep_finish (&proxy_block);
292 }