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 }
|