diff options
Diffstat (limited to 'src/namestore/gnunet-namestore-fcfsd.c')
-rw-r--r-- | src/namestore/gnunet-namestore-fcfsd.c | 1594 |
1 files changed, 733 insertions, 861 deletions
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c index 313aea6fc..ec99d13e5 100644 --- a/src/namestore/gnunet-namestore-fcfsd.c +++ b/src/namestore/gnunet-namestore-fcfsd.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2012-2014 GNUnet e.V. | 3 | Copyright (C) 2012-2021 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software: you can redistribute it and/or modify it | 5 | GNUnet is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Affero General Public License as published | 6 | under the terms of the GNU Affero General Public License as published |
@@ -17,19 +17,13 @@ | |||
17 | 17 | ||
18 | SPDX-License-Identifier: AGPL3.0-or-later | 18 | SPDX-License-Identifier: AGPL3.0-or-later |
19 | */ | 19 | */ |
20 | |||
20 | /** | 21 | /** |
21 | * @file gnunet-namestore-fcfsd.c | 22 | * @file gnunet-namestore-fcfsd.c |
22 | * @brief HTTP daemon that offers first-come-first-serve GNS domain registration | 23 | * @brief HTTP daemon that offers first-come-first-serve GNS domain registration |
23 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
24 | * | ||
25 | * TODO: | ||
26 | * - need to track active zone info requests so we can cancel them | ||
27 | * during shutdown, right? | ||
28 | * - the code currently contains a 'race' between checking that the | ||
29 | * domain name is available and allocating it to the new public key | ||
30 | * (should this race be solved by namestore or by fcfsd?) | ||
31 | * - nicer error reporting to browser | ||
32 | */ | 25 | */ |
26 | |||
33 | #include "platform.h" | 27 | #include "platform.h" |
34 | #include <microhttpd.h> | 28 | #include <microhttpd.h> |
35 | #include "gnunet_util_lib.h" | 29 | #include "gnunet_util_lib.h" |
@@ -37,735 +31,618 @@ | |||
37 | #include "gnunet_gnsrecord_lib.h" | 31 | #include "gnunet_gnsrecord_lib.h" |
38 | #include "gnunet_namestore_service.h" | 32 | #include "gnunet_namestore_service.h" |
39 | #include "gnunet_mhd_compat.h" | 33 | #include "gnunet_mhd_compat.h" |
34 | #include "gnunet_json_lib.h" | ||
40 | 35 | ||
41 | /** | 36 | /** |
42 | * Invalid method page. | 37 | * Structure representing a static page. |
43 | */ | 38 | * "Static" means that the server does not process the page before sending it |
44 | #define METHOD_ERROR \ | 39 | * to the client. Clients can still process the received data, for example |
45 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>Illegal request</title></head><body>Go away.</body></html>" | 40 | * because there are scripting elements within. |
46 | |||
47 | /** | ||
48 | * Front page. (/) | ||
49 | */ | ||
50 | #define MAIN_PAGE \ | ||
51 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>GNUnet FCFS Authority Name Registration Service</title></head><body><form action=\"S\" method=\"post\">What is your desired domain name? (at most 63 lowercase characters, no dots allowed.) <input type=\"text\" name=\"domain\" /> <p> What is your public key? (Copy from gnunet-setup.) <input type=\"text\" name=\"pkey\" /> <input type=\"submit\" value=\"Next\" /><br/><a href=./Zoneinfo> List of all registered names </a></body></html>" | ||
52 | |||
53 | /** | ||
54 | * Second page (/S) | ||
55 | */ | ||
56 | #define SUBMIT_PAGE \ | ||
57 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>%s</title></head><body>%s</body></html>" | ||
58 | |||
59 | /** | ||
60 | * Fcfs zoneinfo page (/Zoneinfo) | ||
61 | */ | ||
62 | #define ZONEINFO_PAGE \ | ||
63 | "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>FCFS Zoneinfo</title></head><body><h1> FCFS Zoneinfo </h1><table border=\"1\"><th>name</th><th>PKEY</th>%s</table></body></html>" | ||
64 | |||
65 | #define FCFS_ZONEINFO_URL "/Zoneinfo" | ||
66 | |||
67 | /** | ||
68 | * Mime type for HTML pages. | ||
69 | */ | ||
70 | #define MIME_HTML "text/html" | ||
71 | |||
72 | /** | ||
73 | * Name of our cookie. | ||
74 | */ | ||
75 | #define COOKIE_NAME "namestore-fcfsd" | ||
76 | |||
77 | #define DEFAULT_ZONEINFO_BUFSIZE 2048 | ||
78 | |||
79 | /** | ||
80 | * Phases a request goes through. | ||
81 | */ | 41 | */ |
82 | enum Phase | 42 | struct StaticPage |
83 | { | 43 | { |
84 | /** | 44 | /** |
85 | * Start phase (parsing POST, checking). | 45 | * Handle to file on disk. |
86 | */ | ||
87 | RP_START = 0, | ||
88 | |||
89 | /** | ||
90 | * Lookup to see if the domain name is taken. | ||
91 | */ | 46 | */ |
92 | RP_LOOKUP, | 47 | struct GNUNET_DISK_FileHandle *handle; |
93 | 48 | ||
94 | /** | 49 | /** |
95 | * Storing of the record. | 50 | * Size in bytes of the file. |
96 | */ | 51 | */ |
97 | RP_PUT, | 52 | uint64_t size; |
98 | 53 | ||
99 | /** | 54 | /** |
100 | * We're done with success. | 55 | * Cached response object to send to clients. |
101 | */ | 56 | */ |
102 | RP_SUCCESS, | 57 | struct MHD_Response *response; |
103 | |||
104 | /** | ||
105 | * Send failure message. | ||
106 | */ | ||
107 | RP_FAIL | ||
108 | }; | 58 | }; |
109 | 59 | ||
110 | |||
111 | /** | 60 | /** |
112 | * Data kept per request. | 61 | * Structure containing some request-specific data. |
113 | */ | 62 | */ |
114 | struct Request | 63 | struct RequestData |
115 | { | 64 | { |
116 | /** | 65 | /** |
117 | * Associated session. | 66 | * The connection this request was sent in. |
118 | */ | ||
119 | // FIXME: struct Session *session; | ||
120 | |||
121 | /** | ||
122 | * Post processor handling form data (IF this is | ||
123 | * a POST request). | ||
124 | */ | 67 | */ |
125 | struct MHD_PostProcessor *pp; | 68 | struct MHD_Connection *c; |
126 | 69 | ||
127 | /** | 70 | /** |
128 | * MHD Connection | 71 | * Body of the response object. |
129 | */ | ||
130 | struct MHD_Connection *con; | ||
131 | /** | ||
132 | * URL to serve in response to this POST (if this request | ||
133 | * was a 'POST') | ||
134 | */ | 72 | */ |
135 | const char *post_url; | 73 | char *body; |
136 | 74 | ||
137 | /** | 75 | /** |
138 | * Active request with the namestore. | 76 | * Length in bytes of the body. |
139 | */ | 77 | */ |
140 | struct GNUNET_NAMESTORE_QueueEntry *qe; | 78 | size_t body_length; |
141 | 79 | ||
142 | /** | 80 | /** |
143 | * Active lookup iterator | 81 | * Response code. |
144 | * TODO: deprecate or fix lookup by label and use above member | ||
145 | */ | 82 | */ |
146 | struct GNUNET_NAMESTORE_ZoneIterator *lookup_it; | 83 | int code; |
147 | /** | ||
148 | * Active iteration with the namestore. | ||
149 | */ | ||
150 | struct GNUNET_NAMESTORE_ZoneIterator *zi; | ||
151 | 84 | ||
152 | /** | 85 | /** |
153 | * Current processing phase. | 86 | * Task started to search for an entry in the namestore. |
154 | */ | 87 | */ |
155 | enum Phase phase; | 88 | struct GNUNET_NAMESTORE_QueueEntry *searching; |
156 | 89 | ||
157 | /** | 90 | /** |
158 | * Domain name submitted via form. | 91 | * Task started to iterate over the namestore. |
159 | */ | 92 | */ |
160 | char domain_name[64]; | 93 | struct GNUNET_NAMESTORE_ZoneIterator *iterating; |
161 | 94 | ||
162 | /** | 95 | /** |
163 | * Public key submitted via form. | 96 | * Pointer used while processing POST data. |
164 | */ | ||
165 | char public_key[128]; | ||
166 | |||
167 | struct GNUNET_IDENTITY_PublicKey pub; | ||
168 | }; | ||
169 | |||
170 | /** | ||
171 | * Zoneinfo request | ||
172 | */ | ||
173 | struct ZoneinfoRequest | ||
174 | { | ||
175 | /** | ||
176 | * List iterator | ||
177 | */ | 97 | */ |
178 | struct GNUNET_NAMESTORE_ZoneIterator *list_it; | 98 | void *ptr; |
179 | 99 | ||
180 | /** | 100 | /** |
181 | * Buffer | 101 | * Name requested to be registered. |
182 | */ | 102 | */ |
183 | char*zoneinfo; | 103 | char *register_name; |
184 | 104 | ||
185 | /** | 105 | /** |
186 | * Buffer length | 106 | * Key (encoded as a string) to be associated with the requested name. |
187 | */ | 107 | */ |
188 | size_t buf_len; | 108 | char *register_key; |
189 | 109 | ||
190 | /** | 110 | /** |
191 | * Buffer write offset | 111 | * Key to be associated with the requested name. |
192 | */ | 112 | */ |
193 | size_t write_offset; | 113 | struct GNUNET_IDENTITY_PublicKey key; |
194 | }; | 114 | }; |
195 | 115 | ||
196 | /** | 116 | /** |
197 | * MHD daemon reference. | 117 | * Name of the zone being managed. |
198 | */ | 118 | */ |
199 | static struct MHD_Daemon *httpd; | 119 | static char *zone = NULL; |
200 | 120 | ||
201 | /** | 121 | /** |
202 | * Main HTTP task. | 122 | * The port the daemon is listening to for HTTP requests. |
203 | */ | 123 | */ |
204 | static struct GNUNET_SCHEDULER_Task *httpd_task; | 124 | static unsigned long long port = 18080; |
205 | 125 | ||
206 | /** | 126 | /** |
207 | * Handle to the namestore. | 127 | * Connection with the namestore service. |
208 | */ | 128 | */ |
209 | static struct GNUNET_NAMESTORE_Handle *ns; | 129 | static struct GNUNET_NAMESTORE_Handle *namestore = NULL; |
210 | 130 | ||
211 | /** | 131 | /** |
212 | * Private key for the fcfsd zone. | 132 | * Connection with the identity service. |
213 | */ | 133 | */ |
214 | static struct GNUNET_IDENTITY_PrivateKey fcfs_zone_pkey; | 134 | static struct GNUNET_IDENTITY_Handle *identity = NULL; |
215 | 135 | ||
216 | /** | 136 | /** |
217 | * Connection to identity service. | 137 | * Private key of the zone. |
218 | */ | 138 | */ |
219 | static struct GNUNET_IDENTITY_Handle *identity; | 139 | static const struct GNUNET_IDENTITY_PrivateKey *zone_key = NULL; |
220 | 140 | ||
221 | /** | 141 | /** |
222 | * Zoneinfo page we currently use. | 142 | * The HTTP daemon. |
223 | */ | 143 | */ |
224 | static struct MHD_Response *info_page; | 144 | static struct MHD_Daemon *httpd = NULL; |
225 | 145 | ||
226 | /** | 146 | /** |
227 | * Task that runs #update_zoneinfo_page peridicially. | 147 | * Task executing the HTTP daemon. |
228 | */ | 148 | */ |
229 | static struct GNUNET_SCHEDULER_Task *uzp_task; | 149 | static struct GNUNET_SCHEDULER_Task *httpd_task = NULL; |
230 | 150 | ||
231 | /** | 151 | /** |
232 | * Request for our ego. | 152 | * The main page, a.k.a. "index.html" |
233 | */ | 153 | */ |
234 | static struct GNUNET_IDENTITY_Operation *id_op; | 154 | static struct StaticPage *main_page = NULL; |
235 | 155 | ||
236 | /** | 156 | /** |
237 | * Port we use for the HTTP server. | 157 | * Page indicating the requested resource could not be found. |
238 | */ | 158 | */ |
239 | static unsigned long long port; | 159 | static struct StaticPage *notfound_page = NULL; |
240 | 160 | ||
241 | /** | 161 | /** |
242 | * Name of the zone we manage. | 162 | * Page indicating the requested resource could not be accessed, and other |
163 | * errors. | ||
243 | */ | 164 | */ |
244 | static char *zone; | 165 | static struct StaticPage *forbidden_page = NULL; |
245 | |||
246 | 166 | ||
247 | /** | 167 | /** |
248 | * Task run whenever HTTP server operations are pending. | 168 | * Task ran at shutdown to clean up everything. |
249 | * | 169 | * |
250 | * @param cls unused | 170 | * @param cls unused |
251 | */ | 171 | */ |
252 | static void | 172 | static void |
253 | do_httpd (void *cls); | 173 | do_shutdown (void *cls) |
174 | { | ||
175 | /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so | ||
176 | calling `GNUNET_DISK_file_close' would generate a spurious warning message | ||
177 | in the log. Since that function does nothing but close the descriptor and | ||
178 | free the allocated memory, After destroying the response all that's left to | ||
179 | do is call `GNUNET_free'. */ | ||
180 | if (NULL != main_page) | ||
181 | { | ||
182 | MHD_destroy_response (main_page->response); | ||
183 | GNUNET_free (main_page->handle); | ||
184 | GNUNET_free (main_page); | ||
185 | } | ||
186 | if (NULL != notfound_page) | ||
187 | { | ||
188 | MHD_destroy_response (main_page->response); | ||
189 | GNUNET_free (main_page->handle); | ||
190 | GNUNET_free (main_page); | ||
191 | } | ||
192 | if (NULL != forbidden_page) | ||
193 | { | ||
194 | MHD_destroy_response (main_page->response); | ||
195 | GNUNET_free (main_page->handle); | ||
196 | GNUNET_free (main_page); | ||
197 | } | ||
254 | 198 | ||
199 | if (NULL != namestore) | ||
200 | { | ||
201 | GNUNET_NAMESTORE_disconnect (namestore); | ||
202 | } | ||
255 | 203 | ||
256 | /** | 204 | if (NULL != identity) |
257 | * Schedule task to run MHD server now. | ||
258 | */ | ||
259 | static void | ||
260 | run_httpd_now () | ||
261 | { | ||
262 | if (NULL != httpd_task) | ||
263 | { | 205 | { |
264 | GNUNET_SCHEDULER_cancel (httpd_task); | 206 | GNUNET_IDENTITY_disconnect (identity); |
265 | httpd_task = NULL; | ||
266 | } | 207 | } |
267 | httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL); | ||
268 | } | 208 | } |
269 | 209 | ||
270 | |||
271 | /** | 210 | /** |
272 | * Create fresh version of zone information. | 211 | * Called when the HTTP server has some pending operations. |
212 | * | ||
213 | * @param cls unused | ||
273 | */ | 214 | */ |
274 | static void | 215 | static void |
275 | update_zoneinfo_page (void *cls); | 216 | do_httpd (void *cls); |
276 | |||
277 | 217 | ||
278 | /** | 218 | /** |
279 | * Function called on error in zone iteration. | 219 | * Schedule a task to run MHD. |
280 | */ | 220 | */ |
281 | static void | 221 | static void |
282 | zone_iteration_error (void *cls) | 222 | run_httpd (void) |
283 | { | 223 | { |
284 | struct ZoneinfoRequest *zr = cls; | 224 | fd_set rs; |
225 | fd_set ws; | ||
226 | fd_set es; | ||
285 | 227 | ||
286 | zr->list_it = NULL; | 228 | struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create (); |
287 | GNUNET_free (zr->zoneinfo); | 229 | struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create (); |
288 | GNUNET_SCHEDULER_cancel (uzp_task); | 230 | struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create (); |
289 | uzp_task = GNUNET_SCHEDULER_add_now (&update_zoneinfo_page, | ||
290 | NULL); | ||
291 | } | ||
292 | 231 | ||
232 | FD_ZERO (&rs); | ||
233 | FD_ZERO (&ws); | ||
234 | FD_ZERO (&es); | ||
235 | |||
236 | int max = -1; | ||
237 | GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); | ||
238 | |||
239 | unsigned MHD_LONG_LONG timeout = 0; | ||
240 | struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL; | ||
241 | if (MHD_YES == MHD_get_timeout (httpd, &timeout)) | ||
242 | { | ||
243 | gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, | ||
244 | timeout); | ||
245 | } | ||
246 | |||
247 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); | ||
248 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); | ||
249 | GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1); | ||
250 | |||
251 | httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
252 | gtime, | ||
253 | grs, | ||
254 | gws, | ||
255 | &do_httpd, | ||
256 | NULL); | ||
257 | GNUNET_NETWORK_fdset_destroy (grs); | ||
258 | GNUNET_NETWORK_fdset_destroy (gws); | ||
259 | GNUNET_NETWORK_fdset_destroy (ges); | ||
260 | } | ||
293 | 261 | ||
294 | /** | 262 | /** |
295 | * Function called once the zone iteration is done. | 263 | * Called when the HTTP server has some pending operations. |
264 | * | ||
265 | * @param cls unused | ||
296 | */ | 266 | */ |
297 | static void | 267 | static void |
298 | zone_iteration_end (void *cls) | 268 | do_httpd (void *cls) |
299 | { | 269 | { |
300 | struct ZoneinfoRequest *zr = cls; | 270 | httpd_task = NULL; |
301 | struct MHD_Response *response; | 271 | MHD_run (httpd); |
302 | char*full_page; | 272 | run_httpd (); |
303 | |||
304 | zr->list_it = NULL; | ||
305 | |||
306 | /* return static form */ | ||
307 | GNUNET_asprintf (&full_page, | ||
308 | ZONEINFO_PAGE, | ||
309 | zr->zoneinfo); | ||
310 | response = MHD_create_response_from_buffer (strlen (full_page), | ||
311 | (void *) full_page, | ||
312 | MHD_RESPMEM_MUST_FREE); | ||
313 | MHD_add_response_header (response, | ||
314 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
315 | MIME_HTML); | ||
316 | MHD_destroy_response (info_page); | ||
317 | info_page = response; | ||
318 | GNUNET_free (zr->zoneinfo); | ||
319 | } | 273 | } |
320 | 274 | ||
275 | static void | ||
276 | run_httpd_now (void) | ||
277 | { | ||
278 | if (NULL != httpd_task) | ||
279 | { | ||
280 | GNUNET_SCHEDULER_cancel (httpd_task); | ||
281 | httpd_task = NULL; | ||
282 | } | ||
283 | httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL); | ||
284 | } | ||
321 | 285 | ||
322 | /** | 286 | /** |
323 | * Process a record that was stored in the namestore, adding | 287 | * Generate a JSON object. |
324 | * the information to the HTML. | ||
325 | * | 288 | * |
326 | * @param cls closure with the `struct ZoneinfoRequest *` | 289 | * @param key the key for the first element |
327 | * @param zone_key private key of the zone; NULL on disconnect | 290 | * @param value the value for the first element |
328 | * @param name label of the records; NULL on disconnect | 291 | * @param ... key-value pairs of the object, terminated by NULL |
329 | * @param rd_len number of entries in @a rd array, 0 if label was deleted | 292 | * @return a JSON string (allocated) |
330 | * @param rd array of records with data to store | ||
331 | */ | 293 | */ |
332 | static void | 294 | static char * |
333 | iterate_cb (void *cls, | 295 | make_json (const char *key, const char *value, ...) |
334 | const struct GNUNET_IDENTITY_PrivateKey *zone_key, | ||
335 | const char *name, | ||
336 | unsigned int rd_len, | ||
337 | const struct GNUNET_GNSRECORD_Data *rd) | ||
338 | { | 296 | { |
339 | struct ZoneinfoRequest *zr = cls; | 297 | va_list args; |
340 | size_t bytes_free; | 298 | va_start(args, value); |
341 | char*pkey; | 299 | |
342 | char*new_buf; | 300 | json_t *obj = NULL; |
343 | 301 | ||
344 | (void) zone_key; | 302 | obj = json_object (); |
345 | if (1 != rd_len) | 303 | if (NULL == key || NULL == value) |
346 | { | 304 | { |
347 | GNUNET_NAMESTORE_zone_iterator_next (zr->list_it, | 305 | va_end (args); |
348 | 1); | 306 | return json_dumps (obj, JSON_COMPACT); |
349 | return; | ||
350 | } | 307 | } |
351 | 308 | ||
352 | if ((GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type) && | 309 | json_object_set (obj, key, json_string (value)); |
353 | (GNUNET_GNSRECORD_TYPE_EDKEY != rd->record_type)) | 310 | |
311 | char *k = va_arg (args, char *); | ||
312 | if (NULL == k) | ||
354 | { | 313 | { |
355 | GNUNET_NAMESTORE_zone_iterator_next (zr->list_it, | 314 | va_end (args); |
356 | 1); | 315 | return json_dumps (obj, JSON_COMPACT); |
357 | return; | ||
358 | } | 316 | } |
359 | 317 | char *v = va_arg (args, char *); | |
360 | bytes_free = zr->buf_len - zr->write_offset; | 318 | if (NULL == v) |
361 | pkey = GNUNET_GNSRECORD_value_to_string (rd->record_type, | ||
362 | rd->data, | ||
363 | rd->data_size); | ||
364 | if (NULL == pkey) | ||
365 | { | 319 | { |
366 | GNUNET_break (0); | 320 | va_end (args); |
367 | GNUNET_NAMESTORE_zone_iterator_next (zr->list_it, | 321 | return json_dumps (obj, JSON_COMPACT); |
368 | 1); | ||
369 | return; | ||
370 | } | 322 | } |
371 | if (bytes_free < (strlen (name) + strlen (pkey) + 40)) | 323 | |
324 | while (NULL != k && NULL != v) | ||
372 | { | 325 | { |
373 | new_buf = GNUNET_malloc (zr->buf_len * 2); | 326 | json_object_set (obj, k, json_string (v)); |
374 | GNUNET_memcpy (new_buf, zr->zoneinfo, zr->write_offset); | 327 | k = va_arg (args, char *); |
375 | GNUNET_free (zr->zoneinfo); | 328 | if (NULL != k) |
376 | zr->zoneinfo = new_buf; | 329 | { |
377 | zr->buf_len *= 2; | 330 | v = va_arg (args, char *); |
331 | } | ||
378 | } | 332 | } |
379 | sprintf (zr->zoneinfo + zr->write_offset, | ||
380 | "<tr><td>%s</td><td>%s</td></tr>", | ||
381 | name, | ||
382 | pkey); | ||
383 | zr->write_offset = strlen (zr->zoneinfo); | ||
384 | GNUNET_NAMESTORE_zone_iterator_next (zr->list_it, | ||
385 | 1); | ||
386 | GNUNET_free (pkey); | ||
387 | } | ||
388 | 333 | ||
334 | va_end (args); | ||
389 | 335 | ||
390 | /** | 336 | char *json = json_dumps (obj, JSON_COMPACT); |
391 | * Handler that returns FCFS zoneinfo page. | 337 | json_decref (obj); |
392 | * | ||
393 | * @param connection connection to use | ||
394 | */ | ||
395 | static int | ||
396 | serve_zoneinfo_page (struct MHD_Connection *connection) | ||
397 | { | ||
398 | return MHD_queue_response (connection, | ||
399 | MHD_HTTP_OK, | ||
400 | info_page); | ||
401 | } | ||
402 | 338 | ||
339 | return json; | ||
340 | } | ||
403 | 341 | ||
404 | /** | 342 | /** |
405 | * Create fresh version of zone information. | 343 | * The namestore search task failed. |
344 | * | ||
345 | * @param cls the request data | ||
406 | */ | 346 | */ |
407 | static void | 347 | static void |
408 | update_zoneinfo_page (void *cls) | 348 | search_error_cb (void *cls) |
409 | { | 349 | { |
410 | static struct ZoneinfoRequest zr; | 350 | struct RequestData *rd = cls; |
411 | 351 | MHD_resume_connection (rd->c); | |
412 | (void) cls; | 352 | rd->searching = NULL; |
413 | uzp_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | 353 | rd->body = make_json ("error", "true", |
414 | &update_zoneinfo_page, | 354 | "message", _ ("can not search the namestore"), |
415 | NULL); | 355 | NULL); |
416 | if (NULL != zr.list_it) | 356 | rd->body_length = strlen (rd->body); |
417 | return; | 357 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
418 | zr.zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE); | 358 | run_httpd_now (); |
419 | zr.buf_len = DEFAULT_ZONEINFO_BUFSIZE; | ||
420 | zr.write_offset = 0; | ||
421 | zr.list_it = GNUNET_NAMESTORE_zone_iteration_start (ns, | ||
422 | &fcfs_zone_pkey, | ||
423 | &zone_iteration_error, | ||
424 | &zr, | ||
425 | &iterate_cb, | ||
426 | &zr, | ||
427 | &zone_iteration_end, | ||
428 | &zr); | ||
429 | } | 359 | } |
430 | 360 | ||
431 | |||
432 | /** | 361 | /** |
433 | * Handler that returns a simple static HTTP page. | 362 | * The lookup terminated with some results. |
434 | * | 363 | * |
435 | * @param connection connection to use | 364 | * @param cls closure |
436 | * @return #MHD_YES on success | 365 | * @param zone the private key of the zone |
366 | * @param label the result label | ||
367 | * @param count number of records found | ||
368 | * @param d records found | ||
437 | */ | 369 | */ |
438 | static int | 370 | static void |
439 | serve_main_page (struct MHD_Connection *connection) | 371 | search_done_cb (void *cls, |
372 | const struct GNUNET_IDENTITY_PrivateKey *zone, | ||
373 | const char *label, | ||
374 | unsigned int count, | ||
375 | const struct GNUNET_GNSRECORD_Data *d) | ||
440 | { | 376 | { |
441 | int ret; | 377 | (void) zone; |
442 | struct MHD_Response *response; | 378 | (void) d; |
443 | 379 | ||
444 | /* return static form */ | 380 | struct RequestData *rd = cls; |
445 | response = MHD_create_response_from_buffer (strlen (MAIN_PAGE), | 381 | MHD_resume_connection (rd->c); |
446 | (void *) MAIN_PAGE, | ||
447 | MHD_RESPMEM_PERSISTENT); | ||
448 | MHD_add_response_header (response, | ||
449 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
450 | MIME_HTML); | ||
451 | ret = MHD_queue_response (connection, | ||
452 | MHD_HTTP_OK, | ||
453 | response); | ||
454 | MHD_destroy_response (response); | ||
455 | return ret; | ||
456 | } | ||
457 | 382 | ||
383 | rd->searching = NULL; | ||
384 | rd->body = make_json ("error", "false", | ||
385 | "free", (0 == count) ? "true" : "false", | ||
386 | NULL); | ||
387 | rd->body_length = strlen (rd->body); | ||
388 | rd->code = MHD_HTTP_OK; | ||
458 | 389 | ||
459 | /** | 390 | run_httpd_now (); |
460 | * Send the 'SUBMIT_PAGE'. | ||
461 | * | ||
462 | * @param info information string to send to the user | ||
463 | * @param request request information | ||
464 | * @param connection connection to use | ||
465 | */ | ||
466 | static int | ||
467 | fill_s_reply (const char *info, | ||
468 | struct Request *request, | ||
469 | struct MHD_Connection *connection) | ||
470 | { | ||
471 | int ret; | ||
472 | char *reply; | ||
473 | struct MHD_Response *response; | ||
474 | |||
475 | (void) request; | ||
476 | GNUNET_asprintf (&reply, | ||
477 | SUBMIT_PAGE, | ||
478 | info, | ||
479 | info); | ||
480 | /* return static form */ | ||
481 | response = MHD_create_response_from_buffer (strlen (reply), | ||
482 | (void *) reply, | ||
483 | MHD_RESPMEM_MUST_FREE); | ||
484 | MHD_add_response_header (response, | ||
485 | MHD_HTTP_HEADER_CONTENT_TYPE, | ||
486 | MIME_HTML); | ||
487 | ret = MHD_queue_response (connection, | ||
488 | MHD_HTTP_OK, | ||
489 | response); | ||
490 | MHD_destroy_response (response); | ||
491 | return ret; | ||
492 | } | 391 | } |
493 | 392 | ||
494 | |||
495 | /** | 393 | /** |
496 | * Iterator over key-value pairs where the value | 394 | * An error occurred while registering a name. |
497 | * maybe made available in increments and/or may | ||
498 | * not be zero-terminated. Used for processing | ||
499 | * POST data. | ||
500 | * | 395 | * |
501 | * @param cls user-specified closure | 396 | * @param cls the connection |
502 | * @param kind type of the value | ||
503 | * @param key 0-terminated key for the value | ||
504 | * @param filename name of the uploaded file, NULL if not known | ||
505 | * @param content_type mime-type of the data, NULL if not known | ||
506 | * @param transfer_encoding encoding of the data, NULL if not known | ||
507 | * @param data pointer to size bytes of data at the | ||
508 | * specified offset | ||
509 | * @param off offset of data in the overall value | ||
510 | * @param size number of bytes in data available | ||
511 | * @return #MHD_YES to continue iterating, | ||
512 | * #MHD_NO to abort the iteration | ||
513 | */ | 397 | */ |
514 | static MHD_RESULT | 398 | static void |
515 | post_iterator (void *cls, | 399 | register_error_cb (void *cls) |
516 | enum MHD_ValueKind kind, | ||
517 | const char *key, | ||
518 | const char *filename, | ||
519 | const char *content_type, | ||
520 | const char *transfer_encoding, | ||
521 | const char *data, | ||
522 | uint64_t off, | ||
523 | size_t size) | ||
524 | { | 400 | { |
525 | struct Request *request = cls; | 401 | struct RequestData *rd = cls; |
526 | 402 | ||
527 | (void) kind; | 403 | MHD_resume_connection (rd->c); |
528 | (void) filename; | 404 | rd->searching = NULL; |
529 | (void) content_type; | 405 | rd->body = make_json ("error", "true", |
530 | (void) transfer_encoding; | 406 | "message", _ ("unable to scan namestore")); |
531 | if (0 == strcmp ("domain", key)) | 407 | rd->body_length = strlen (rd->body); |
532 | { | 408 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
533 | if (size + off >= sizeof(request->domain_name)) | 409 | run_httpd_now (); |
534 | size = sizeof(request->domain_name) - off - 1; | ||
535 | GNUNET_memcpy (&request->domain_name[off], | ||
536 | data, | ||
537 | size); | ||
538 | request->domain_name[size + off] = '\0'; | ||
539 | return MHD_YES; | ||
540 | } | ||
541 | if (0 == strcmp ("pkey", key)) | ||
542 | { | ||
543 | if (size + off >= sizeof(request->public_key)) | ||
544 | size = sizeof(request->public_key) - off - 1; | ||
545 | GNUNET_memcpy (&request->public_key[off], | ||
546 | data, | ||
547 | size); | ||
548 | request->public_key[size + off] = '\0'; | ||
549 | return MHD_YES; | ||
550 | } | ||
551 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
552 | _ ("Unsupported form value `%s'\n"), | ||
553 | key); | ||
554 | return MHD_YES; | ||
555 | } | 410 | } |
556 | 411 | ||
557 | |||
558 | /** | 412 | /** |
559 | * Continuation called to notify client about result of the | 413 | * A name/key pair has been successfully registered, or maybe not. |
560 | * operation. | ||
561 | * | 414 | * |
562 | * @param cls closure | 415 | * @param cls the connection |
563 | * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) | 416 | * @param status result of the operation |
564 | * #GNUNET_NO if content was already there | 417 | * @param emsg error message if any |
565 | * #GNUNET_YES (or other positive value) on success | ||
566 | * @param emsg NULL on success, otherwise an error message | ||
567 | */ | 418 | */ |
568 | static void | 419 | static void |
569 | put_continuation (void *cls, | 420 | register_done_cb (void *cls, |
570 | int32_t success, | 421 | int32_t status, |
571 | const char *emsg) | 422 | const char *emsg) |
572 | { | 423 | { |
573 | struct Request *request = cls; | 424 | struct RequestData *rd = cls; |
425 | |||
426 | MHD_resume_connection (rd->c); | ||
427 | rd->searching = NULL; | ||
574 | 428 | ||
575 | request->qe = NULL; | 429 | if (GNUNET_SYSERR == status || GNUNET_NO == status) |
576 | if (0 >= success) | ||
577 | { | 430 | { |
578 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 431 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
579 | _ ("Failed to create record for domain `%s': %s\n"), | 432 | _ ("Failed to create record for `%s': %s\n"), |
580 | request->domain_name, | 433 | rd->register_name, |
581 | emsg); | 434 | emsg); |
582 | request->phase = RP_FAIL; | 435 | rd->body = make_json ("error", "true", |
436 | "message", emsg); | ||
437 | rd->body_length = strlen (rd->body); | ||
438 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
583 | } | 439 | } |
584 | else | 440 | else |
585 | request->phase = RP_SUCCESS; | 441 | { |
586 | MHD_resume_connection (request->con); | 442 | rd->body = make_json ("error", "false", |
443 | "message", _ ("no errors")); | ||
444 | rd->body_length = strlen (rd->body); | ||
445 | rd->code = MHD_HTTP_OK; | ||
446 | } | ||
447 | |||
587 | run_httpd_now (); | 448 | run_httpd_now (); |
588 | } | 449 | } |
589 | 450 | ||
590 | |||
591 | /** | 451 | /** |
592 | * Function called if we had an error in zone-to-name mapping. | 452 | * Attempt to register the requested name. |
453 | * | ||
454 | * @param cls the connection | ||
455 | * @param key the zone key | ||
456 | * @param label name of the record | ||
457 | * @param count number of records found | ||
458 | * @param d records | ||
593 | */ | 459 | */ |
594 | static void | 460 | static void |
595 | zone_to_name_error (void *cls) | 461 | register_do_cb (void *cls, |
462 | const struct GNUNET_IDENTITY_PrivateKey *key, | ||
463 | const char *label, | ||
464 | unsigned int count, | ||
465 | const struct GNUNET_GNSRECORD_Data *d) | ||
596 | { | 466 | { |
597 | struct Request *request = cls; | 467 | (void) key; |
468 | (void) d; | ||
598 | 469 | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 470 | struct RequestData *rd = cls; |
600 | _ ("Error when mapping zone to name\n")); | ||
601 | request->phase = RP_FAIL; | ||
602 | MHD_resume_connection (request->con); | ||
603 | run_httpd_now (); | ||
604 | } | ||
605 | 471 | ||
472 | rd->searching = NULL; | ||
606 | 473 | ||
607 | /** | 474 | if (0 != count) |
608 | * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record. | ||
609 | * | ||
610 | * @param cls closure | ||
611 | * @param zone_key public key of the zone | ||
612 | * @param name name that is being mapped (at most 255 characters long) | ||
613 | * @param rd_count number of entries in @a rd array | ||
614 | * @param rd array of records with data to store | ||
615 | */ | ||
616 | static void | ||
617 | zone_to_name_cb (void *cls, | ||
618 | const struct GNUNET_IDENTITY_PrivateKey *zone_key, | ||
619 | const char *name, | ||
620 | unsigned int rd_count, | ||
621 | const struct GNUNET_GNSRECORD_Data *rd) | ||
622 | { | ||
623 | struct Request *request = cls; | ||
624 | struct GNUNET_GNSRECORD_Data r; | ||
625 | char *rdata; | ||
626 | |||
627 | (void) rd; | ||
628 | (void) zone_key; | ||
629 | request->qe = NULL; | ||
630 | if (0 != rd_count) | ||
631 | { | 475 | { |
632 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 476 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
633 | _ ("Found existing name `%s' for the given key\n"), | 477 | _ ("The requested key `%s' exists as `%s'\n"), |
634 | name); | 478 | rd->register_key, |
635 | request->phase = RP_FAIL; | 479 | label); |
636 | MHD_resume_connection (request->con); | 480 | |
481 | MHD_resume_connection (rd->c); | ||
482 | rd->searching = NULL; | ||
483 | rd->body = make_json ("error", "true", | ||
484 | "message", _ ("key exists")); | ||
485 | rd->body_length = strlen (rd->body); | ||
486 | rd->code = MHD_HTTP_FORBIDDEN; | ||
637 | run_httpd_now (); | 487 | run_httpd_now (); |
638 | return; | 488 | return; |
639 | } | 489 | } |
640 | if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&request->pub, | 490 | |
641 | &rdata, | 491 | struct GNUNET_GNSRECORD_Data gd; |
642 | &r.data_size, | 492 | char *gdraw = NULL; |
643 | &r.record_type)) | 493 | |
494 | if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&(rd->key), | ||
495 | &gdraw, | ||
496 | &(gd.data_size), | ||
497 | &(gd.record_type))) | ||
644 | { | 498 | { |
645 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 499 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
646 | _ ("Error creating record data.\n")); | 500 | _ ("Error creating record data\n")); |
647 | request->phase = RP_FAIL; | 501 | MHD_resume_connection (rd->c); |
648 | MHD_resume_connection (request->con); | 502 | rd->searching = NULL; |
503 | rd->body = make_json ("error", "true", | ||
504 | "message", _ ("unable to store record")); | ||
505 | rd->body_length = strlen (rd->body); | ||
506 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
649 | run_httpd_now (); | 507 | run_httpd_now (); |
650 | return; | 508 | return; |
651 | } | 509 | } |
652 | 510 | ||
653 | r.data = rdata; | 511 | gd.data = gdraw; |
654 | r.expiration_time = UINT64_MAX; | 512 | gd.expiration_time = UINT64_MAX; |
655 | r.flags = GNUNET_GNSRECORD_RF_NONE; | 513 | gd.flags = GNUNET_GNSRECORD_RF_NONE; |
656 | request->qe = GNUNET_NAMESTORE_records_store (ns, | ||
657 | &fcfs_zone_pkey, | ||
658 | request->domain_name, | ||
659 | 1, &r, | ||
660 | &put_continuation, | ||
661 | request); | ||
662 | GNUNET_free (rdata); | ||
663 | } | ||
664 | 514 | ||
515 | rd->searching = GNUNET_NAMESTORE_records_store (namestore, | ||
516 | zone_key, | ||
517 | rd->register_name, | ||
518 | 1, | ||
519 | &gd, | ||
520 | ®ister_done_cb, | ||
521 | rd); | ||
522 | |||
523 | GNUNET_free (gdraw); | ||
524 | } | ||
665 | 525 | ||
666 | /** | 526 | /** |
667 | * We encountered an error in the name lookup. | 527 | * An error occurred while iterating the namestore. |
528 | * | ||
529 | * @param cls the connection | ||
668 | */ | 530 | */ |
669 | static void | 531 | static void |
670 | lookup_it_error (void *cls) | 532 | iterate_error_cb (void *cls) |
671 | { | 533 | { |
672 | struct Request *request = cls; | 534 | struct RequestData *rd = cls; |
673 | 535 | ||
674 | MHD_resume_connection (request->con); | 536 | MHD_resume_connection (rd->c); |
675 | request->qe = NULL; | 537 | rd->iterating = NULL; |
676 | request->phase = RP_FAIL; | 538 | rd->body = make_json ("error", "true", |
539 | "message", _ ("unable to scan namestore")); | ||
540 | rd->body_length = strlen (rd->body); | ||
541 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
677 | run_httpd_now (); | 542 | run_httpd_now (); |
678 | } | 543 | } |
679 | 544 | ||
680 | |||
681 | /** | 545 | /** |
682 | * We got a block back from the namestore. Decrypt it | 546 | * A block was received from the namestore. |
683 | * and continue to process the result. | ||
684 | * | 547 | * |
685 | * @param cls the 'struct Request' we are processing | 548 | * @param cls the connection |
686 | * @param zonekey private key of the zone; NULL on disconnect | 549 | * @param key the zone key |
687 | * @param label label of the records; NULL on disconnect | 550 | * @param label the records' label |
688 | * @param rd_count number of entries in @a rd array, 0 if label was deleted | 551 | * @param count number of records found |
689 | * @param rd array of records with data to store | 552 | * @param d the found records |
690 | */ | 553 | */ |
691 | static void | 554 | static void |
692 | lookup_it_processor (void *cls, | 555 | iterate_do_cb (void *cls, |
693 | const struct GNUNET_IDENTITY_PrivateKey *zonekey, | 556 | const struct GNUNET_IDENTITY_PrivateKey *key, |
694 | const char *label, | 557 | const char *label, |
695 | unsigned int rd_count, | 558 | unsigned int count, |
696 | const struct GNUNET_GNSRECORD_Data *rd) | 559 | const struct GNUNET_GNSRECORD_Data *d) |
697 | { | 560 | { |
698 | struct Request *request = cls; | 561 | (void) key; |
699 | |||
700 | (void) label; | 562 | (void) label; |
701 | (void) rd; | 563 | (void) d; |
702 | (void) zonekey; | 564 | |
703 | if (0 == strcmp (label, request->domain_name)) | 565 | struct RequestData *rd = cls; |
566 | |||
567 | if (0 == strcmp (label, rd->register_name)) | ||
704 | { | 568 | { |
705 | GNUNET_break (0 != rd_count); | 569 | GNUNET_break (0 != count); |
706 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 570 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
707 | _ ("Found %u existing records for domain `%s'\n"), | 571 | _ ("Requested name `%s' exists with `%u' records\n"), |
708 | rd_count, | 572 | rd->register_name, |
709 | request->domain_name); | 573 | count); |
710 | request->phase = RP_FAIL; | 574 | |
575 | MHD_resume_connection (rd->c); | ||
576 | rd->body = make_json ("error", "true", | ||
577 | "message", _ ("name exists\n")); | ||
578 | rd->body_length = strlen (rd->body); | ||
579 | rd->code = MHD_HTTP_FORBIDDEN; | ||
580 | GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating); | ||
581 | run_httpd_now (); | ||
582 | return; | ||
711 | } | 583 | } |
712 | GNUNET_NAMESTORE_zone_iterator_next (request->lookup_it, 1); | ||
713 | } | ||
714 | 584 | ||
585 | GNUNET_NAMESTORE_zone_iterator_next (rd->iterating, 1); | ||
586 | } | ||
715 | 587 | ||
588 | /** | ||
589 | * All entries in the namestore have been iterated over. | ||
590 | * | ||
591 | * @param cls the connection | ||
592 | */ | ||
716 | static void | 593 | static void |
717 | lookup_it_finished (void *cls) | 594 | iterate_done_cb (void *cls) |
718 | { | 595 | { |
719 | struct Request *request = cls; | 596 | struct RequestData *rd = cls; |
720 | 597 | ||
721 | if (RP_FAIL == request->phase) | 598 | rd->iterating = NULL; |
722 | { | 599 | |
723 | MHD_resume_connection (request->con); | 600 | /* See if the key was not registered already */ |
724 | run_httpd_now (); | 601 | rd->searching = GNUNET_NAMESTORE_zone_to_name (namestore, |
725 | return; | 602 | zone_key, |
726 | } | 603 | &(rd->key), |
727 | if (GNUNET_OK != | 604 | ®ister_error_cb, |
728 | GNUNET_IDENTITY_public_key_from_string (request->public_key, | 605 | rd, |
729 | &request->pub)) | 606 | ®ister_do_cb, |
730 | { | 607 | rd); |
731 | GNUNET_break (0); | ||
732 | request->phase = RP_FAIL; | ||
733 | MHD_resume_connection (request->con); | ||
734 | run_httpd_now (); | ||
735 | return; | ||
736 | } | ||
737 | request->qe = GNUNET_NAMESTORE_zone_to_name (ns, | ||
738 | &fcfs_zone_pkey, | ||
739 | &request->pub, | ||
740 | &zone_to_name_error, | ||
741 | request, | ||
742 | &zone_to_name_cb, | ||
743 | request); | ||
744 | } | 608 | } |
745 | 609 | ||
610 | /** | ||
611 | * Generate a response containing JSON and send it to the client. | ||
612 | * | ||
613 | * @param c the connection | ||
614 | * @param body the response body | ||
615 | * @param length the body length in bytes | ||
616 | * @param code the response code | ||
617 | * @return MHD_NO on error | ||
618 | */ | ||
619 | static MHD_RESULT | ||
620 | serve_json (struct MHD_Connection *c, | ||
621 | char *body, | ||
622 | size_t length, | ||
623 | int code) | ||
624 | { | ||
625 | struct MHD_Response *response = | ||
626 | MHD_create_response_from_buffer (length, | ||
627 | body, | ||
628 | MHD_RESPMEM_PERSISTENT); | ||
629 | MHD_RESULT r = MHD_queue_response (c, code, response); | ||
630 | MHD_destroy_response (response); | ||
631 | return r; | ||
632 | } | ||
746 | 633 | ||
747 | /** | 634 | /** |
748 | * Main MHD callback for handling requests. | 635 | * Send a response back to a connected client. |
749 | * | 636 | * |
750 | * @param cls unused | 637 | * @param cls unused |
751 | * @param connection MHD connection handle | 638 | * @param connection the connection with the client |
752 | * @param url the requested url | 639 | * @param url the requested address |
753 | * @param method the HTTP method used ("GET", "PUT", etc.) | 640 | * @param method the HTTP method used |
754 | * @param version the HTTP version string ("HTTP/1.1" for version 1.1, etc.) | 641 | * @param version the protocol version (including the "HTTP/" part) |
755 | * @param upload_data the data being uploaded (excluding HEADERS, | 642 | * @param upload_data data sent with a POST request |
756 | * for a POST that fits into memory and that is encoded | 643 | * @param upload_data_size length in bytes of the POST data |
757 | * with a supported encoding, the POST data will NOT be | 644 | * @param ptr used to pass data between request handling phases |
758 | * given in upload_data and is instead available as | 645 | * @return MHD_NO on error |
759 | * part of MHD_get_connection_values; very large POST | ||
760 | * data *will* be made available incrementally in | ||
761 | * upload_data) | ||
762 | * @param upload_data_size set initially to the size of the | ||
763 | * @a upload_data provided; the method must update this | ||
764 | * value to the number of bytes NOT processed; | ||
765 | * @param ptr pointer to location where we store the 'struct Request' | ||
766 | * @return #MHD_YES if the connection was handled successfully, | ||
767 | * #MHD_NO if the socket must be closed due to a serious | ||
768 | * error while handling the request | ||
769 | */ | 646 | */ |
770 | static MHD_RESULT | 647 | static MHD_RESULT |
771 | create_response (void *cls, | 648 | create_response (void *cls, |
@@ -777,300 +654,249 @@ create_response (void *cls, | |||
777 | size_t *upload_data_size, | 654 | size_t *upload_data_size, |
778 | void **ptr) | 655 | void **ptr) |
779 | { | 656 | { |
780 | struct MHD_Response *response; | ||
781 | struct Request *request; | ||
782 | struct GNUNET_IDENTITY_PublicKey pub; | ||
783 | MHD_RESULT ret; | ||
784 | |||
785 | (void) cls; | 657 | (void) cls; |
786 | (void) version; | 658 | (void) version; |
787 | if ((0 == strcmp (method, MHD_HTTP_METHOD_GET)) || | 659 | |
788 | (0 == strcmp (method, MHD_HTTP_METHOD_HEAD))) | 660 | struct RequestData *rd = *ptr; |
789 | { | 661 | |
790 | if (0 == strcmp (url, FCFS_ZONEINFO_URL)) | 662 | if (0 == strcmp (method, MHD_HTTP_METHOD_GET)) |
791 | ret = serve_zoneinfo_page (connection); | ||
792 | else | ||
793 | ret = serve_main_page (connection); | ||
794 | if (ret != MHD_YES) | ||
795 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
796 | _ ("Failed to create page for `%s'\n"), | ||
797 | url); | ||
798 | return ret; | ||
799 | } | ||
800 | if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) | ||
801 | { | 663 | { |
802 | request = *ptr; | 664 | /* Handle a previously suspended request */ |
803 | if (NULL == request) | 665 | if (NULL != rd) |
666 | { | ||
667 | return serve_json (rd->c, rd->body, rd->body_length, rd->code); | ||
668 | } | ||
669 | |||
670 | if (0 == strcmp ("/", url)) | ||
804 | { | 671 | { |
805 | request = GNUNET_new (struct Request); | 672 | return MHD_queue_response (connection, |
806 | request->con = connection; | 673 | MHD_HTTP_OK, |
807 | *ptr = request; | 674 | main_page->response); |
808 | request->pp = MHD_create_post_processor (connection, | 675 | } |
809 | 1024, | 676 | |
810 | &post_iterator, | 677 | if (0 == strcmp ("/search", url)) |
811 | request); | 678 | { |
812 | if (NULL == request->pp) | 679 | const char *name = MHD_lookup_connection_value (connection, |
680 | MHD_GET_ARGUMENT_KIND, | ||
681 | "name"); | ||
682 | if (NULL == name) | ||
813 | { | 683 | { |
814 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 684 | return MHD_queue_response (connection, |
815 | _ ("Failed to setup post processor for `%s'\n"), | 685 | MHD_HTTP_BAD_REQUEST, |
816 | url); | 686 | forbidden_page->response); |
817 | return MHD_NO; /* internal error */ | ||
818 | } | 687 | } |
688 | |||
689 | MHD_suspend_connection (connection); | ||
690 | rd = GNUNET_new (struct RequestData); | ||
691 | rd->c = connection; | ||
692 | rd->searching = GNUNET_NAMESTORE_records_lookup (namestore, | ||
693 | zone_key, | ||
694 | name, | ||
695 | &search_error_cb, | ||
696 | rd, | ||
697 | &search_done_cb, | ||
698 | rd); | ||
699 | *ptr = rd; | ||
819 | return MHD_YES; | 700 | return MHD_YES; |
820 | } | 701 | } |
821 | if (NULL != request->pp) | 702 | |
703 | return MHD_queue_response (connection, | ||
704 | MHD_HTTP_NOT_FOUND, | ||
705 | notfound_page->response); | ||
706 | } | ||
707 | |||
708 | if (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) | ||
709 | { | ||
710 | /* We take a shortcut here by always serving the main page: starting a | ||
711 | namestore lookup, allocating the necessary resources, waiting for the | ||
712 | lookup to complete and then discard everything just because it was a HEAD | ||
713 | and thus only the headers are significative, is an unnecessary waste of | ||
714 | resources. The handling of this method could be smarter, for example by | ||
715 | sending a proper content type header based on the endpoint, but this is | ||
716 | not a service in which HEAD requests are significant, so there's no need | ||
717 | to spend too much time here. */ | ||
718 | return MHD_queue_response (connection, | ||
719 | MHD_HTTP_OK, | ||
720 | main_page->response); | ||
721 | } | ||
722 | |||
723 | if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) | ||
724 | { | ||
725 | if (0 == strcmp ("/register", url)) | ||
822 | { | 726 | { |
823 | /* evaluate POST data */ | 727 | /* Handle a previously suspended request */ |
824 | MHD_post_process (request->pp, | 728 | if (NULL != rd && NULL != rd->body) |
825 | upload_data, | ||
826 | *upload_data_size); | ||
827 | if (0 != *upload_data_size) | ||
828 | { | 729 | { |
829 | *upload_data_size = 0; | 730 | return serve_json (rd->c, rd->body, rd->body_length, rd->code); |
830 | return MHD_YES; | ||
831 | } | 731 | } |
832 | /* done with POST data, serve response */ | 732 | |
833 | MHD_destroy_post_processor (request->pp); | 733 | if (NULL == rd) |
834 | request->pp = NULL; | ||
835 | } | ||
836 | if (GNUNET_OK != | ||
837 | GNUNET_IDENTITY_public_key_from_string (request->public_key, | ||
838 | &pub)) | ||
839 | { | ||
840 | /* parse error */ | ||
841 | return fill_s_reply ("Failed to parse given public key", | ||
842 | request, connection); | ||
843 | } | ||
844 | switch (request->phase) | ||
845 | { | ||
846 | case RP_START: | ||
847 | if (NULL != strchr (request->domain_name, (int) '.')) | ||
848 | { | 734 | { |
849 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 735 | rd = GNUNET_new (struct RequestData); |
850 | _ ("Domain name must not contain `.'\n")); | 736 | rd->c = connection; |
851 | request->phase = RP_FAIL; | 737 | rd->body = NULL; |
852 | return fill_s_reply ("Domain name must not contain `.', sorry.", | 738 | rd->ptr = NULL; |
853 | request, | 739 | *ptr = rd; |
854 | connection); | ||
855 | } | 740 | } |
856 | if (NULL != strchr (request->domain_name, (int) '+')) | 741 | |
742 | json_t *json = NULL; | ||
743 | enum GNUNET_JSON_PostResult result = | ||
744 | GNUNET_JSON_post_parser (32 * 1024, | ||
745 | connection, | ||
746 | &(rd->ptr), | ||
747 | upload_data, | ||
748 | upload_data_size, | ||
749 | &json); | ||
750 | |||
751 | switch (result) | ||
857 | { | 752 | { |
858 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 753 | case GNUNET_JSON_PR_CONTINUE: |
859 | _ ("Domain name must not contain `+'\n")); | 754 | /* Keep processing POST data */ |
860 | request->phase = RP_FAIL; | 755 | return MHD_YES; |
861 | return fill_s_reply ("Domain name must not contain `+', sorry.", | 756 | case GNUNET_JSON_PR_OUT_OF_MEMORY: |
862 | request, connection); | 757 | case GNUNET_JSON_PR_REQUEST_TOO_LARGE: |
758 | rd->body = make_json ("error", "true", | ||
759 | "message", _ ("unable to process submitted data")); | ||
760 | rd->body_length = strlen (rd->body); | ||
761 | rd->code = MHD_HTTP_PAYLOAD_TOO_LARGE; | ||
762 | return MHD_YES; | ||
763 | case GNUNET_JSON_PR_JSON_INVALID: | ||
764 | rd->body = make_json ("error", "true", | ||
765 | "message", _ ("the submitted data is invalid")); | ||
766 | rd->body_length = strlen (rd->body); | ||
767 | rd->code = MHD_HTTP_BAD_REQUEST; | ||
768 | return MHD_YES; | ||
769 | default: | ||
770 | break; | ||
863 | } | 771 | } |
864 | request->phase = RP_LOOKUP; | ||
865 | MHD_suspend_connection (request->con); | ||
866 | request->lookup_it | ||
867 | = GNUNET_NAMESTORE_zone_iteration_start (ns, | ||
868 | &fcfs_zone_pkey, | ||
869 | &lookup_it_error, | ||
870 | request, | ||
871 | &lookup_it_processor, | ||
872 | request, | ||
873 | &lookup_it_finished, | ||
874 | request); | ||
875 | break; | ||
876 | |||
877 | case RP_LOOKUP: | ||
878 | break; | ||
879 | |||
880 | case RP_PUT: | ||
881 | break; | ||
882 | |||
883 | case RP_FAIL: | ||
884 | return fill_s_reply ("Request failed, sorry.", | ||
885 | request, connection); | ||
886 | |||
887 | case RP_SUCCESS: | ||
888 | return fill_s_reply ("Success.", | ||
889 | request, connection); | ||
890 | |||
891 | default: | ||
892 | GNUNET_break (0); | ||
893 | return MHD_NO; | ||
894 | } | ||
895 | return MHD_YES; /* will have a reply later... */ | ||
896 | } | ||
897 | /* unsupported HTTP method */ | ||
898 | response = MHD_create_response_from_buffer (strlen (METHOD_ERROR), | ||
899 | (void *) METHOD_ERROR, | ||
900 | MHD_RESPMEM_PERSISTENT); | ||
901 | ret = MHD_queue_response (connection, | ||
902 | MHD_HTTP_NOT_ACCEPTABLE, | ||
903 | response); | ||
904 | MHD_destroy_response (response); | ||
905 | return ret; | ||
906 | } | ||
907 | 772 | ||
773 | /* POST data has been read in its entirety */ | ||
908 | 774 | ||
909 | /** | 775 | const char *name = json_string_value(json_object_get(json, "name")); |
910 | * Callback called upon completion of a request. | 776 | const char *key = json_string_value(json_object_get(json, "key")); |
911 | * Decrements session reference counter. | 777 | if (NULL == name || NULL == key || 0 == strlen (name) || 0 == strlen (key)) |
912 | * | 778 | { |
913 | * @param cls not used | 779 | json_decref (json); |
914 | * @param connection connection that completed | 780 | rd->body = make_json ("error", "true", |
915 | * @param con_cls session handle | 781 | "message", _ ("invalid parameters")); |
916 | * @param toe status code | 782 | rd->body_length = strlen (rd->body); |
917 | */ | 783 | rd->code = MHD_HTTP_BAD_REQUEST; |
918 | static void | 784 | return MHD_YES; |
919 | request_completed_callback (void *cls, | 785 | } |
920 | struct MHD_Connection *connection, | ||
921 | void **con_cls, | ||
922 | enum MHD_RequestTerminationCode toe) | ||
923 | { | ||
924 | struct Request *request = *con_cls; | ||
925 | 786 | ||
926 | (void) cls; | 787 | rd->register_name = strdup (name); |
927 | (void) connection; | 788 | rd->register_key = strdup (key); |
928 | (void) toe; | ||
929 | if (NULL == request) | ||
930 | return; | ||
931 | if (NULL != request->pp) | ||
932 | MHD_destroy_post_processor (request->pp); | ||
933 | if (NULL != request->qe) | ||
934 | GNUNET_NAMESTORE_cancel (request->qe); | ||
935 | GNUNET_free (request); | ||
936 | } | ||
937 | 789 | ||
790 | json_decref (json); | ||
791 | GNUNET_JSON_post_parser_cleanup (rd->ptr); | ||
938 | 792 | ||
939 | #define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG | 793 | if (NULL != strchr (rd->register_name, '.') || |
794 | NULL != strchr (rd->register_name, '+')) | ||
795 | { | ||
796 | rd->body = make_json ("error", "true", | ||
797 | "message", _ ("invalid name")); | ||
798 | rd->body_length = strlen (rd->body); | ||
799 | rd->code = MHD_HTTP_BAD_REQUEST; | ||
800 | } | ||
940 | 801 | ||
802 | if (GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (rd->register_key, | ||
803 | &(rd->key))) | ||
804 | { | ||
805 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
806 | _ ("Unable to parse key %s\n"), | ||
807 | rd->register_key); | ||
808 | |||
809 | rd->body = make_json ("error", "true", | ||
810 | "message", _ ("unable to parse key")); | ||
811 | rd->body_length = strlen (rd->body); | ||
812 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
813 | return MHD_YES; | ||
814 | } | ||
941 | 815 | ||
942 | /** | 816 | MHD_suspend_connection (connection); |
943 | * Schedule tasks to run MHD server. | 817 | /* See if the requested name is free */ |
944 | */ | 818 | rd->iterating = |
945 | static void | 819 | GNUNET_NAMESTORE_zone_iteration_start (namestore, |
946 | run_httpd () | 820 | zone_key, |
947 | { | 821 | &iterate_error_cb, |
948 | fd_set rs; | 822 | rd, |
949 | fd_set ws; | 823 | &iterate_do_cb, |
950 | fd_set es; | 824 | rd, |
951 | struct GNUNET_NETWORK_FDSet *wrs; | 825 | &iterate_done_cb, |
952 | struct GNUNET_NETWORK_FDSet *wws; | 826 | rd); |
953 | struct GNUNET_NETWORK_FDSet *wes; | 827 | return MHD_YES; |
954 | int max; | 828 | } |
955 | int haveto; | ||
956 | UNSIGNED_MHD_LONG_LONG timeout; | ||
957 | struct GNUNET_TIME_Relative tv; | ||
958 | 829 | ||
959 | FD_ZERO (&rs); | 830 | return MHD_queue_response (connection, |
960 | FD_ZERO (&ws); | 831 | MHD_HTTP_FORBIDDEN, |
961 | FD_ZERO (&es); | 832 | forbidden_page->response); |
962 | wrs = GNUNET_NETWORK_fdset_create (); | 833 | } |
963 | wes = GNUNET_NETWORK_fdset_create (); | ||
964 | wws = GNUNET_NETWORK_fdset_create (); | ||
965 | max = -1; | ||
966 | GNUNET_assert (MHD_YES == | ||
967 | MHD_get_fdset (httpd, | ||
968 | &rs, | ||
969 | &ws, | ||
970 | &es, | ||
971 | &max)); | ||
972 | haveto = MHD_get_timeout (httpd, | ||
973 | &timeout); | ||
974 | if (haveto == MHD_YES) | ||
975 | tv.rel_value_us = (uint64_t) timeout * 1000LL; | ||
976 | else | ||
977 | tv = GNUNET_TIME_UNIT_FOREVER_REL; | ||
978 | GNUNET_NETWORK_fdset_copy_native (wrs, | ||
979 | &rs, | ||
980 | max + 1); | ||
981 | GNUNET_NETWORK_fdset_copy_native (wws, | ||
982 | &ws, | ||
983 | max + 1); | ||
984 | GNUNET_NETWORK_fdset_copy_native (wes, | ||
985 | &es, | ||
986 | max + 1); | ||
987 | httpd_task = | ||
988 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
989 | tv, | ||
990 | wrs, | ||
991 | wws, | ||
992 | &do_httpd, | ||
993 | NULL); | ||
994 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
995 | GNUNET_NETWORK_fdset_destroy (wws); | ||
996 | GNUNET_NETWORK_fdset_destroy (wes); | ||
997 | } | ||
998 | 834 | ||
835 | return MHD_queue_response (connection, | ||
836 | MHD_HTTP_NOT_IMPLEMENTED, | ||
837 | forbidden_page->response); | ||
838 | } | ||
999 | 839 | ||
1000 | /** | 840 | /** |
1001 | * Task run whenever HTTP server operations are pending. | 841 | * Called when a request is completed. |
1002 | * | 842 | * |
1003 | * @param cls unused | 843 | * @param cls unused |
844 | * @param connection the connection | ||
845 | * @param ptr connection-specific data | ||
846 | * @param status status code | ||
1004 | */ | 847 | */ |
1005 | static void | 848 | static void |
1006 | do_httpd (void *cls) | 849 | completed_cb (void *cls, |
850 | struct MHD_Connection *connection, | ||
851 | void **ptr, | ||
852 | enum MHD_RequestTerminationCode status) | ||
1007 | { | 853 | { |
1008 | (void) cls; | 854 | (void) cls; |
1009 | httpd_task = NULL; | 855 | (void) connection; |
1010 | MHD_run (httpd); | 856 | (void) status; |
1011 | run_httpd (); | ||
1012 | } | ||
1013 | 857 | ||
858 | struct RequestData *rd = *ptr; | ||
1014 | 859 | ||
1015 | /** | 860 | if (NULL == rd) |
1016 | * Task run on shutdown. Cleans up everything. | ||
1017 | * | ||
1018 | * @param cls unused | ||
1019 | */ | ||
1020 | static void | ||
1021 | do_shutdown (void *cls) | ||
1022 | { | ||
1023 | (void) cls; | ||
1024 | if (NULL != httpd_task) | ||
1025 | { | 861 | { |
1026 | GNUNET_SCHEDULER_cancel (httpd_task); | 862 | return; |
1027 | httpd_task = NULL; | ||
1028 | } | 863 | } |
1029 | if (NULL != uzp_task) | 864 | |
865 | if (NULL == rd->body) | ||
1030 | { | 866 | { |
1031 | GNUNET_SCHEDULER_cancel (uzp_task); | 867 | GNUNET_free (rd->body); |
1032 | uzp_task = NULL; | ||
1033 | } | 868 | } |
1034 | if (NULL != ns) | 869 | |
870 | if (NULL != rd->searching) | ||
1035 | { | 871 | { |
1036 | GNUNET_NAMESTORE_disconnect (ns); | 872 | GNUNET_NAMESTORE_cancel (rd->searching); |
1037 | ns = NULL; | ||
1038 | } | 873 | } |
1039 | if (NULL != httpd) | 874 | |
875 | if (NULL != rd->register_name) | ||
1040 | { | 876 | { |
1041 | MHD_stop_daemon (httpd); | 877 | GNUNET_free (rd->register_name); |
1042 | httpd = NULL; | ||
1043 | } | 878 | } |
1044 | if (NULL != id_op) | 879 | |
880 | if (NULL != rd->register_key) | ||
1045 | { | 881 | { |
1046 | GNUNET_IDENTITY_cancel (id_op); | 882 | GNUNET_free (rd->register_key); |
1047 | id_op = NULL; | ||
1048 | } | 883 | } |
1049 | if (NULL != identity) | 884 | |
885 | if (NULL != rd->iterating) | ||
1050 | { | 886 | { |
1051 | GNUNET_IDENTITY_disconnect (identity); | 887 | GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating); |
1052 | identity = NULL; | ||
1053 | } | 888 | } |
1054 | } | ||
1055 | 889 | ||
890 | GNUNET_free (rd); | ||
891 | } | ||
1056 | 892 | ||
1057 | /** | 893 | /** |
1058 | * Method called to inform about the egos of this peer. | 894 | * Called for each ego provided by the identity service. |
1059 | * | ||
1060 | * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get, this | ||
1061 | * function is only called ONCE, and 'NULL' being passed in @a ego does | ||
1062 | * indicate an error (for example because name is taken or no default value is | ||
1063 | * known). If @a ego is non-NULL and if '*ctx' is set in those callbacks, the | ||
1064 | * value WILL be passed to a subsequent call to the identity callback of | ||
1065 | * #GNUNET_IDENTITY_connect (if that one was not NULL). | ||
1066 | * | 895 | * |
1067 | * @param cls closure, NULL | 896 | * @param cls closure |
1068 | * @param ego ego handle | 897 | * @param ego the ego |
1069 | * @param ctx context for application to store data for this ego | 898 | * @param ctx application-provided data for the ego |
1070 | * (during the lifetime of this process, initially NULL) | 899 | * @param name the ego name |
1071 | * @param name name assigned by the user for this ego, | ||
1072 | * NULL if the user just deleted the ego and it | ||
1073 | * must thus no longer be used | ||
1074 | */ | 900 | */ |
1075 | static void | 901 | static void |
1076 | identity_cb (void *cls, | 902 | identity_cb (void *cls, |
@@ -1078,15 +904,14 @@ identity_cb (void *cls, | |||
1078 | void **ctx, | 904 | void **ctx, |
1079 | const char *name) | 905 | const char *name) |
1080 | { | 906 | { |
1081 | int options; | ||
1082 | |||
1083 | (void) cls; | 907 | (void) cls; |
1084 | (void) ctx; | 908 | (void) ctx; |
1085 | if (NULL == name) | 909 | |
1086 | return; | 910 | if (NULL == name || 0 != strcmp (name, zone)) |
1087 | if (0 != strcmp (name, | 911 | { |
1088 | zone)) | ||
1089 | return; | 912 | return; |
913 | } | ||
914 | |||
1090 | if (NULL == ego) | 915 | if (NULL == ego) |
1091 | { | 916 | { |
1092 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 917 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
@@ -1094,30 +919,24 @@ identity_cb (void *cls, | |||
1094 | GNUNET_SCHEDULER_shutdown (); | 919 | GNUNET_SCHEDULER_shutdown (); |
1095 | return; | 920 | return; |
1096 | } | 921 | } |
1097 | fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego); | ||
1098 | 922 | ||
1099 | options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME; | 923 | zone_key = GNUNET_IDENTITY_ego_get_private_key (ego); |
924 | |||
925 | int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME; | ||
1100 | do | 926 | do |
1101 | { | 927 | { |
1102 | httpd = MHD_start_daemon (options, | 928 | httpd = MHD_start_daemon (flags, |
1103 | (uint16_t) port, | 929 | (uint16_t) port, |
1104 | NULL, NULL, | 930 | NULL, NULL, |
1105 | &create_response, NULL, | 931 | &create_response, NULL, |
1106 | MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, | 932 | MHD_OPTION_CONNECTION_LIMIT, 128, |
1107 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned | 933 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1, |
1108 | int) 1, | 934 | MHD_OPTION_CONNECTION_TIMEOUT, 4 * 1024, |
1109 | MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, | 935 | MHD_OPTION_NOTIFY_COMPLETED, &completed_cb, NULL, |
1110 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 | ||
1111 | * | ||
1112 | 1024), | ||
1113 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1114 | &request_completed_callback, NULL, | ||
1115 | MHD_OPTION_END); | 936 | MHD_OPTION_END); |
1116 | if (MHD_USE_DEBUG == options) | 937 | flags = MHD_USE_DEBUG; |
1117 | break; | 938 | } while (NULL == httpd && flags != MHD_USE_DEBUG); |
1118 | options = MHD_USE_DEBUG; | 939 | |
1119 | } | ||
1120 | while (NULL == httpd); | ||
1121 | if (NULL == httpd) | 940 | if (NULL == httpd) |
1122 | { | 941 | { |
1123 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 942 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
@@ -1125,105 +944,158 @@ identity_cb (void *cls, | |||
1125 | GNUNET_SCHEDULER_shutdown (); | 944 | GNUNET_SCHEDULER_shutdown (); |
1126 | return; | 945 | return; |
1127 | } | 946 | } |
947 | |||
1128 | run_httpd (); | 948 | run_httpd (); |
1129 | } | 949 | } |
1130 | 950 | ||
951 | /** | ||
952 | * Open a file on disk and generate a response object for it. | ||
953 | * | ||
954 | * @param name name of the file to open | ||
955 | * @param basedir directory where the file is located | ||
956 | * @return #GNUNET_SYSERR on error | ||
957 | */ | ||
958 | static struct StaticPage * | ||
959 | open_static_page (const char *name, const char *basedir) | ||
960 | { | ||
961 | char *fullname = NULL; | ||
962 | GNUNET_asprintf (&fullname, "%s/fcfsd-%s", basedir, name); | ||
963 | |||
964 | struct GNUNET_DISK_FileHandle *f = | ||
965 | GNUNET_DISK_file_open (fullname, | ||
966 | GNUNET_DISK_OPEN_READ, | ||
967 | GNUNET_DISK_PERM_NONE); | ||
968 | GNUNET_free (fullname); | ||
969 | |||
970 | if (NULL == f) | ||
971 | { | ||
972 | return NULL; | ||
973 | } | ||
974 | |||
975 | off_t size = 0; | ||
976 | if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size)) | ||
977 | { | ||
978 | GNUNET_DISK_file_close (f); | ||
979 | return NULL; | ||
980 | } | ||
981 | |||
982 | struct MHD_Response *response = | ||
983 | MHD_create_response_from_fd64 (size, | ||
984 | f->fd); | ||
985 | |||
986 | if (NULL == response) | ||
987 | { | ||
988 | GNUNET_DISK_file_close (f); | ||
989 | return NULL; | ||
990 | } | ||
991 | |||
992 | struct StaticPage *page = GNUNET_new (struct StaticPage); | ||
993 | page->handle = f; | ||
994 | page->size = (uint64_t) size; | ||
995 | page->response = response; | ||
996 | return page; | ||
997 | } | ||
1131 | 998 | ||
1132 | /** | 999 | /** |
1133 | * Main function that will be run. | 1000 | * Called after the service is up. |
1134 | * | 1001 | * |
1135 | * @param cls closure | 1002 | * @param cls closure |
1136 | * @param args remaining command-line arguments | 1003 | * @param args remaining command line arguments |
1137 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | 1004 | * @param cfgfile name of the configuration file |
1138 | * @param cfg configuration | 1005 | * @param cfg the service configuration |
1139 | */ | 1006 | */ |
1140 | static void | 1007 | static void |
1141 | run (void *cls, | 1008 | run_service (void *cls, |
1142 | char *const *args, | 1009 | char *const *args, |
1143 | const char *cfgfile, | 1010 | const char *cfgfile, |
1144 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 1011 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
1145 | { | 1012 | { |
1146 | (void) cls; | 1013 | (void) cls; |
1147 | (void) args; | 1014 | (void) args; |
1148 | (void) cfgfile; | 1015 | (void) cfgfile; |
1149 | if (GNUNET_OK != | 1016 | |
1150 | GNUNET_CONFIGURATION_get_value_number (cfg, | 1017 | GNUNET_log_setup ("fcfsd", "WARNING", NULL); |
1151 | "fcfsd", | 1018 | |
1152 | "HTTPPORT", | 1019 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, |
1153 | &port)) | 1020 | "fcfsd", |
1021 | "HTTPPORT", | ||
1022 | &port)) | ||
1154 | { | 1023 | { |
1155 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | 1024 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1156 | "fcfsd", "HTTPPORT"); | 1025 | _ ("No port specified, using default value\n")); |
1157 | return; | ||
1158 | } | 1026 | } |
1159 | ns = GNUNET_NAMESTORE_connect (cfg); | 1027 | |
1160 | if (NULL == ns) | 1028 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); |
1029 | |||
1030 | namestore = GNUNET_NAMESTORE_connect (cfg); | ||
1031 | if (NULL == namestore) | ||
1161 | { | 1032 | { |
1162 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1033 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1163 | _ ("Failed to connect to namestore\n")); | 1034 | _ ("Failed to connect to namestore\n")); |
1035 | GNUNET_SCHEDULER_shutdown (); | ||
1164 | return; | 1036 | return; |
1165 | } | 1037 | } |
1166 | identity = GNUNET_IDENTITY_connect (cfg, | 1038 | |
1167 | &identity_cb, | 1039 | identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL); |
1168 | NULL); | ||
1169 | if (NULL == identity) | 1040 | if (NULL == identity) |
1170 | { | 1041 | { |
1171 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1042 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1172 | _ ("Failed to connect to identity\n")); | 1043 | _ ("Failed to connect to identity\n")); |
1044 | GNUNET_SCHEDULER_shutdown (); | ||
1173 | return; | 1045 | return; |
1174 | } | 1046 | } |
1175 | uzp_task = GNUNET_SCHEDULER_add_now (&update_zoneinfo_page, | ||
1176 | NULL); | ||
1177 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, | ||
1178 | NULL); | ||
1179 | } | ||
1180 | 1047 | ||
1048 | char *basedir = NULL; | ||
1049 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
1050 | "fcfsd", | ||
1051 | "HTMLDIR", | ||
1052 | &basedir)) | ||
1053 | { | ||
1054 | basedir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); | ||
1055 | } | ||
1056 | |||
1057 | main_page = open_static_page ("index.html", basedir); | ||
1058 | notfound_page = open_static_page ("notfound.html", basedir); | ||
1059 | forbidden_page = open_static_page ("forbidden.html", basedir); | ||
1060 | |||
1061 | GNUNET_free (basedir); | ||
1062 | |||
1063 | if (NULL == main_page || NULL == notfound_page || NULL == forbidden_page) | ||
1064 | { | ||
1065 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1066 | _ ("Unable to set up the daemon\n")); | ||
1067 | GNUNET_SCHEDULER_shutdown (); | ||
1068 | return; | ||
1069 | } | ||
1070 | } | ||
1181 | 1071 | ||
1182 | /** | 1072 | /** |
1183 | * The main function for the fcfs daemon. | 1073 | * The main function of the fcfs daemon. |
1184 | * | 1074 | * |
1185 | * @param argc number of arguments from the command line | 1075 | * @param argc number of arguments from the command line |
1186 | * @param argv command line arguments | 1076 | * @parsm argv the command line argumens |
1187 | * @return 0 ok, 1 on error | 1077 | * @return 0 successful exit, a different value otherwise |
1188 | */ | 1078 | */ |
1189 | int | 1079 | int |
1190 | main (int argc, | 1080 | main (int argc, char *const *argv) |
1191 | char *const *argv) | ||
1192 | { | 1081 | { |
1193 | struct GNUNET_GETOPT_CommandLineOption options[] = { | 1082 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
1194 | GNUNET_GETOPT_option_mandatory | 1083 | GNUNET_GETOPT_option_mandatory |
1195 | (GNUNET_GETOPT_option_string ('z', | 1084 | (GNUNET_GETOPT_option_string ('z', |
1196 | "zone", | 1085 | "zone", |
1197 | "EGO", | 1086 | "EGO", |
1198 | gettext_noop ( | 1087 | gettext_noop ("name of the zone managed by FCFSD"), |
1199 | "name of the zone that is to be managed by FCFSD"), | 1088 | &zone)), |
1200 | &zone)), | ||
1201 | GNUNET_GETOPT_OPTION_END | 1089 | GNUNET_GETOPT_OPTION_END |
1202 | }; | 1090 | }; |
1203 | int ret; | ||
1204 | |||
1205 | if (GNUNET_OK != | ||
1206 | GNUNET_STRINGS_get_utf8_args (argc, argv, | ||
1207 | &argc, &argv)) | ||
1208 | return 2; | ||
1209 | |||
1210 | GNUNET_log_setup ("fcfsd", | ||
1211 | "WARNING", | ||
1212 | NULL); | ||
1213 | ret = | ||
1214 | (GNUNET_OK == | ||
1215 | GNUNET_PROGRAM_run (argc, | ||
1216 | argv, | ||
1217 | "gnunet-namestore-fcfsd", | ||
1218 | _ ( | ||
1219 | "GNU Name System First Come First Serve name registration service"), | ||
1220 | options, | ||
1221 | &run, NULL)) ? 0 : 1; | ||
1222 | GNUNET_free_nz ((void *) argv); | ||
1223 | // FIXME | ||
1224 | // GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey); | ||
1225 | return ret; | ||
1226 | } | ||
1227 | 1091 | ||
1228 | 1092 | return ((GNUNET_OK == GNUNET_PROGRAM_run (argc, | |
1229 | /* end of gnunet-namestore-fcfsd.c */ | 1093 | argv, |
1094 | "gnunet-namestore-fcfsd", | ||
1095 | _ ("GNU Name System First-Come-First-Served name registration service"), | ||
1096 | options, | ||
1097 | &run_service, | ||
1098 | NULL)) ? | ||
1099 | 0 : | ||
1100 | 1); | ||
1101 | } | ||