Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:ad8d5b8a2dde |
---|---|
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 */ | |
16 | |
17 #include "gt_gnutella.h" | |
18 | |
19 #include "gt_node.h" | |
20 #include "gt_packet.h" /* htovs() */ | |
21 | |
22 #include "transfer/push_proxy.h" | |
23 | |
24 /*****************************************************************************/ | |
25 | |
26 /* | |
27 * All this GGEP stuff will move somewhere else soon. Just haven't decided | |
28 * where to put it. | |
29 */ | |
30 | |
31 /*****************************************************************************/ | |
32 | |
33 #define PROXY_DEBUG gt_config_get_int("push_proxy/debug=0") | |
34 | |
35 /*****************************************************************************/ | |
36 | |
37 #define GGEP_HDR_LEN (1) /* 0xc3 */ | |
38 #define GGEP_EXT_MAX_LEN (63) /* use only a single len chunk for now */ | |
39 | |
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 }; | |
45 | |
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 */ | |
52 | |
53 /* lower 4 bits is identifier length */ | |
54 }; | |
55 | |
56 /*****************************************************************************/ | |
57 | |
58 struct proxy_addr | |
59 { | |
60 in_addr_t ipv4; | |
61 in_port_t port; | |
62 }; | |
63 | |
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; | |
72 | |
73 /*****************************************************************************/ | |
74 | |
75 static ggep_t proxy_block; | |
76 static Dataset *proxies; | |
77 | |
78 /*****************************************************************************/ | |
79 | |
80 static BOOL ggep_grow (ggep_t *ggep, size_t sz) | |
81 { | |
82 uint8_t *new_block; | |
83 size_t new_size; | |
84 | |
85 new_size = ggep->block_len + sz; | |
86 if (!(new_block = realloc (ggep->block, new_size))) | |
87 return FALSE; | |
88 | |
89 ggep->block = new_block; | |
90 ggep->block_len = new_size; | |
91 | |
92 return TRUE; | |
93 } | |
94 | |
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; | |
101 | |
102 if (!(ggep->block = malloc (1))) | |
103 return FALSE; | |
104 | |
105 /* append magic byte */ | |
106 ggep->block[0] = 0xc3; | |
107 | |
108 return TRUE; | |
109 } | |
110 | |
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 } | |
118 | |
119 assert (ggep->offset + data_size <= ggep->block_len); | |
120 memcpy (&ggep->block[ggep->offset], data, data_size); | |
121 ggep->offset += data_size; | |
122 } | |
123 | |
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; | |
131 | |
132 id_len = strlen (id) & 0x0f; | |
133 | |
134 /* disable Encoding, Compression, LastExtension bits, len in low 4 bits */ | |
135 ext_flags = id_len; | |
136 | |
137 /* track position of last extension for setting LastExtension bit */ | |
138 ggep->last_ext_offset = ggep->offset; | |
139 | |
140 /* extension flag header */ | |
141 ggep_append (ggep, &ext_flags, 1); | |
142 | |
143 /* extension identifier */ | |
144 ggep_append (ggep, id, id_len); | |
145 | |
146 assert (data_len <= GGEP_EXT_MAX_LEN); | |
147 ext_data_len = data_len | GGEP_LEN_LAST; /* add last length chunk flag */ | |
148 | |
149 /* the extension length */ | |
150 ggep_append (ggep, &ext_data_len, 1); | |
151 | |
152 /* the extension data */ | |
153 ggep_append (ggep, data, data_len); | |
154 | |
155 if (ggep->error) | |
156 return FALSE; | |
157 | |
158 return TRUE; | |
159 } | |
160 | |
161 static BOOL ggep_seal (ggep_t *ggep) | |
162 { | |
163 if (ggep->last_ext_offset == 0) | |
164 return FALSE; | |
165 | |
166 /* set the LastExtension bit on the last extension */ | |
167 ggep->block[ggep->last_ext_offset] |= GGEP_EXTF_LAST; | |
168 return TRUE; | |
169 } | |
170 | |
171 static void ggep_finish (ggep_t *ggep) | |
172 { | |
173 free (ggep->block); | |
174 } | |
175 | |
176 /*****************************************************************************/ | |
177 | |
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; | |
184 | |
185 port = htovs (proxy->port); | |
186 | |
187 if (*push_ext_len + 6 >= GGEP_EXT_MAX_LEN) | |
188 return; | |
189 | |
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 } | |
194 | |
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]; | |
200 | |
201 ggep_finish (ggep); | |
202 | |
203 if (ggep_init (ggep) == FALSE) | |
204 return; | |
205 | |
206 cmp[0] = push_ext; | |
207 cmp[1] = &push_ext_len; | |
208 | |
209 push_ext_len = 0; | |
210 dataset_foreach (proxies, DS_FOREACH(ds_add_proxy), cmp); | |
211 assert (push_ext_len <= GGEP_EXT_MAX_LEN); | |
212 | |
213 if (ggep_append_extension (ggep, "PUSH", push_ext, push_ext_len) == FALSE) | |
214 return; | |
215 | |
216 ggep_seal (ggep); | |
217 } | |
218 | |
219 /*****************************************************************************/ | |
220 | |
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; | |
226 | |
227 addr.ipv4 = ipv4; | |
228 addr.port = port; | |
229 | |
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 } | |
238 | |
239 if (add) | |
240 dataset_insert (&proxies, &node, sizeof(node), &addr, sizeof(addr)); | |
241 else | |
242 dataset_remove (proxies, &node, sizeof(node)); | |
243 | |
244 update_block (&proxy_block); | |
245 } | |
246 | |
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); | |
251 | |
252 push_proxy_change (node, ipv4, port, TRUE); | |
253 node->push_proxy_ip = ipv4; | |
254 node->push_proxy_port = port; | |
255 } | |
256 | |
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 } | |
267 | |
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; | |
272 | |
273 *block = proxy_block.block; | |
274 *block_len = proxy_block.block_len; | |
275 | |
276 return TRUE; | |
277 } | |
278 | |
279 /*****************************************************************************/ | |
280 | |
281 void gt_push_proxy_init (void) | |
282 { | |
283 ggep_init (&proxy_block); | |
284 } | |
285 | |
286 void gt_push_proxy_cleanup (void) | |
287 { | |
288 dataset_clear (proxies); | |
289 proxies = NULL; | |
290 | |
291 ggep_finish (&proxy_block); | |
292 } |