diff options
author | Alessio Vanni <vannilla@firemail.cc> | 2021-05-19 18:59:55 +0200 |
---|---|---|
committer | Alessio Vanni <vannilla@firemail.cc> | 2021-05-19 18:59:55 +0200 |
commit | 0c7e226462d4e96d88189faaf3979c2dacdcfe3f (patch) | |
tree | d01954959d577381c7a8ed5b6a89c5fdf42ae197 /src | |
parent | 00c21152e81c10dff640ec932127e74ea8bc25ac (diff) | |
parent | c68abd271cce537ced900193e59a7d5373c1bf83 (diff) | |
download | gnunet-0c7e226462d4e96d88189faaf3979c2dacdcfe3f.tar.gz gnunet-0c7e226462d4e96d88189faaf3979c2dacdcfe3f.zip |
-Merge branch 'dev/vanni/fcfsd'
Diffstat (limited to 'src')
-rw-r--r-- | src/namestore/Makefile.am | 3 | ||||
-rw-r--r-- | src/namestore/gnunet-namestore-fcfsd.c | 1607 |
2 files changed, 748 insertions, 862 deletions
diff --git a/src/namestore/Makefile.am b/src/namestore/Makefile.am index df4e5d662..61bcfbaf8 100644 --- a/src/namestore/Makefile.am +++ b/src/namestore/Makefile.am | |||
@@ -182,7 +182,8 @@ gnunet_namestore_fcfsd_LDADD = $(MHD_LIBS) \ | |||
182 | $(top_builddir)/src/identity/libgnunetidentity.la \ | 182 | $(top_builddir)/src/identity/libgnunetidentity.la \ |
183 | libgnunetnamestore.la \ | 183 | libgnunetnamestore.la \ |
184 | $(top_builddir)/src/util/libgnunetutil.la \ | 184 | $(top_builddir)/src/util/libgnunetutil.la \ |
185 | $(GN_LIBINTL) | 185 | $(top_builddir)/src/json/libgnunetjson.la \ |
186 | $(GN_LIBINTL) -ljansson | ||
186 | gnunet_namestore_fcfsd_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) | 187 | gnunet_namestore_fcfsd_CFLAGS = $(MHD_CFLAGS) $(AM_CFLAGS) |
187 | 188 | ||
188 | 189 | ||
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c index 313aea6fc..e1fa0a0a6 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,625 @@ | |||
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 | NULL); |
532 | { | 408 | rd->body_length = strlen (rd->body); |
533 | if (size + off >= sizeof(request->domain_name)) | 409 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; |
534 | size = sizeof(request->domain_name) - off - 1; | 410 | run_httpd_now (); |
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 | } | 411 | } |
556 | 412 | ||
557 | |||
558 | /** | 413 | /** |
559 | * Continuation called to notify client about result of the | 414 | * A name/key pair has been successfully registered, or maybe not. |
560 | * operation. | ||
561 | * | 415 | * |
562 | * @param cls closure | 416 | * @param cls the connection |
563 | * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) | 417 | * @param status result of the operation |
564 | * #GNUNET_NO if content was already there | 418 | * @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 | */ | 419 | */ |
568 | static void | 420 | static void |
569 | put_continuation (void *cls, | 421 | register_done_cb (void *cls, |
570 | int32_t success, | 422 | int32_t status, |
571 | const char *emsg) | 423 | const char *emsg) |
572 | { | 424 | { |
573 | struct Request *request = cls; | 425 | struct RequestData *rd = cls; |
426 | |||
427 | MHD_resume_connection (rd->c); | ||
428 | rd->searching = NULL; | ||
574 | 429 | ||
575 | request->qe = NULL; | 430 | if (GNUNET_SYSERR == status || GNUNET_NO == status) |
576 | if (0 >= success) | ||
577 | { | 431 | { |
578 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 432 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
579 | _ ("Failed to create record for domain `%s': %s\n"), | 433 | _ ("Failed to create record for `%s': %s\n"), |
580 | request->domain_name, | 434 | rd->register_name, |
581 | emsg); | 435 | emsg); |
582 | request->phase = RP_FAIL; | 436 | rd->body = make_json ("error", "true", |
437 | "message", emsg, | ||
438 | NULL); | ||
439 | rd->body_length = strlen (rd->body); | ||
440 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
583 | } | 441 | } |
584 | else | 442 | else |
585 | request->phase = RP_SUCCESS; | 443 | { |
586 | MHD_resume_connection (request->con); | 444 | rd->body = make_json ("error", "false", |
445 | "message", _ ("no errors"), | ||
446 | NULL); | ||
447 | rd->body_length = strlen (rd->body); | ||
448 | rd->code = MHD_HTTP_OK; | ||
449 | } | ||
450 | |||
587 | run_httpd_now (); | 451 | run_httpd_now (); |
588 | } | 452 | } |
589 | 453 | ||
590 | |||
591 | /** | 454 | /** |
592 | * Function called if we had an error in zone-to-name mapping. | 455 | * Attempt to register the requested name. |
456 | * | ||
457 | * @param cls the connection | ||
458 | * @param key the zone key | ||
459 | * @param label name of the record | ||
460 | * @param count number of records found | ||
461 | * @param d records | ||
593 | */ | 462 | */ |
594 | static void | 463 | static void |
595 | zone_to_name_error (void *cls) | 464 | register_do_cb (void *cls, |
465 | const struct GNUNET_IDENTITY_PrivateKey *key, | ||
466 | const char *label, | ||
467 | unsigned int count, | ||
468 | const struct GNUNET_GNSRECORD_Data *d) | ||
596 | { | 469 | { |
597 | struct Request *request = cls; | 470 | (void) key; |
471 | (void) d; | ||
598 | 472 | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 473 | 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 | 474 | ||
475 | rd->searching = NULL; | ||
606 | 476 | ||
607 | /** | 477 | 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 | { | 478 | { |
632 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 479 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
633 | _ ("Found existing name `%s' for the given key\n"), | 480 | _ ("The requested key `%s' exists as `%s'\n"), |
634 | name); | 481 | rd->register_key, |
635 | request->phase = RP_FAIL; | 482 | label); |
636 | MHD_resume_connection (request->con); | 483 | |
484 | MHD_resume_connection (rd->c); | ||
485 | rd->searching = NULL; | ||
486 | rd->body = make_json ("error", "true", | ||
487 | "message", _ ("key exists"), | ||
488 | NULL); | ||
489 | rd->body_length = strlen (rd->body); | ||
490 | rd->code = MHD_HTTP_FORBIDDEN; | ||
637 | run_httpd_now (); | 491 | run_httpd_now (); |
638 | return; | 492 | return; |
639 | } | 493 | } |
640 | if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&request->pub, | 494 | |
641 | &rdata, | 495 | struct GNUNET_GNSRECORD_Data gd; |
642 | &r.data_size, | 496 | char *gdraw = NULL; |
643 | &r.record_type)) | 497 | |
498 | if (GNUNET_OK != GNUNET_GNSRECORD_data_from_identity (&(rd->key), | ||
499 | &gdraw, | ||
500 | &(gd.data_size), | ||
501 | &(gd.record_type))) | ||
644 | { | 502 | { |
645 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 503 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
646 | _ ("Error creating record data.\n")); | 504 | _ ("Error creating record data\n")); |
647 | request->phase = RP_FAIL; | 505 | MHD_resume_connection (rd->c); |
648 | MHD_resume_connection (request->con); | 506 | rd->searching = NULL; |
507 | rd->body = make_json ("error", "true", | ||
508 | "message", _ ("unable to store record"), | ||
509 | NULL); | ||
510 | rd->body_length = strlen (rd->body); | ||
511 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
649 | run_httpd_now (); | 512 | run_httpd_now (); |
650 | return; | 513 | return; |
651 | } | 514 | } |
652 | 515 | ||
653 | r.data = rdata; | 516 | gd.data = gdraw; |
654 | r.expiration_time = UINT64_MAX; | 517 | gd.expiration_time = UINT64_MAX; |
655 | r.flags = GNUNET_GNSRECORD_RF_NONE; | 518 | 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 | 519 | ||
520 | rd->searching = GNUNET_NAMESTORE_records_store (namestore, | ||
521 | zone_key, | ||
522 | rd->register_name, | ||
523 | 1, | ||
524 | &gd, | ||
525 | ®ister_done_cb, | ||
526 | rd); | ||
527 | |||
528 | GNUNET_free (gdraw); | ||
529 | } | ||
665 | 530 | ||
666 | /** | 531 | /** |
667 | * We encountered an error in the name lookup. | 532 | * An error occurred while iterating the namestore. |
533 | * | ||
534 | * @param cls the connection | ||
668 | */ | 535 | */ |
669 | static void | 536 | static void |
670 | lookup_it_error (void *cls) | 537 | iterate_error_cb (void *cls) |
671 | { | 538 | { |
672 | struct Request *request = cls; | 539 | struct RequestData *rd = cls; |
673 | 540 | ||
674 | MHD_resume_connection (request->con); | 541 | MHD_resume_connection (rd->c); |
675 | request->qe = NULL; | 542 | rd->iterating = NULL; |
676 | request->phase = RP_FAIL; | 543 | rd->body = make_json ("error", "true", |
544 | "message", _ ("unable to scan namestore"), | ||
545 | NULL); | ||
546 | rd->body_length = strlen (rd->body); | ||
547 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
677 | run_httpd_now (); | 548 | run_httpd_now (); |
678 | } | 549 | } |
679 | 550 | ||
680 | |||
681 | /** | 551 | /** |
682 | * We got a block back from the namestore. Decrypt it | 552 | * A block was received from the namestore. |
683 | * and continue to process the result. | ||
684 | * | 553 | * |
685 | * @param cls the 'struct Request' we are processing | 554 | * @param cls the connection |
686 | * @param zonekey private key of the zone; NULL on disconnect | 555 | * @param key the zone key |
687 | * @param label label of the records; NULL on disconnect | 556 | * @param label the records' label |
688 | * @param rd_count number of entries in @a rd array, 0 if label was deleted | 557 | * @param count number of records found |
689 | * @param rd array of records with data to store | 558 | * @param d the found records |
690 | */ | 559 | */ |
691 | static void | 560 | static void |
692 | lookup_it_processor (void *cls, | 561 | iterate_do_cb (void *cls, |
693 | const struct GNUNET_IDENTITY_PrivateKey *zonekey, | 562 | const struct GNUNET_IDENTITY_PrivateKey *key, |
694 | const char *label, | 563 | const char *label, |
695 | unsigned int rd_count, | 564 | unsigned int count, |
696 | const struct GNUNET_GNSRECORD_Data *rd) | 565 | const struct GNUNET_GNSRECORD_Data *d) |
697 | { | 566 | { |
698 | struct Request *request = cls; | 567 | (void) key; |
699 | |||
700 | (void) label; | 568 | (void) label; |
701 | (void) rd; | 569 | (void) d; |
702 | (void) zonekey; | 570 | |
703 | if (0 == strcmp (label, request->domain_name)) | 571 | struct RequestData *rd = cls; |
572 | |||
573 | if (0 == strcmp (label, rd->register_name)) | ||
704 | { | 574 | { |
705 | GNUNET_break (0 != rd_count); | 575 | GNUNET_break (0 != count); |
706 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 576 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
707 | _ ("Found %u existing records for domain `%s'\n"), | 577 | _ ("Requested name `%s' exists with `%u' records\n"), |
708 | rd_count, | 578 | rd->register_name, |
709 | request->domain_name); | 579 | count); |
710 | request->phase = RP_FAIL; | 580 | |
581 | MHD_resume_connection (rd->c); | ||
582 | rd->body = make_json ("error", "true", | ||
583 | "message", _ ("name exists\n"), | ||
584 | NULL); | ||
585 | rd->body_length = strlen (rd->body); | ||
586 | rd->code = MHD_HTTP_FORBIDDEN; | ||
587 | GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating); | ||
588 | run_httpd_now (); | ||
589 | return; | ||
711 | } | 590 | } |
712 | GNUNET_NAMESTORE_zone_iterator_next (request->lookup_it, 1); | ||
713 | } | ||
714 | 591 | ||
592 | GNUNET_NAMESTORE_zone_iterator_next (rd->iterating, 1); | ||
593 | } | ||
715 | 594 | ||
595 | /** | ||
596 | * All entries in the namestore have been iterated over. | ||
597 | * | ||
598 | * @param cls the connection | ||
599 | */ | ||
716 | static void | 600 | static void |
717 | lookup_it_finished (void *cls) | 601 | iterate_done_cb (void *cls) |
718 | { | 602 | { |
719 | struct Request *request = cls; | 603 | struct RequestData *rd = cls; |
720 | 604 | ||
721 | if (RP_FAIL == request->phase) | 605 | rd->iterating = NULL; |
722 | { | 606 | |
723 | MHD_resume_connection (request->con); | 607 | /* See if the key was not registered already */ |
724 | run_httpd_now (); | 608 | rd->searching = GNUNET_NAMESTORE_zone_to_name (namestore, |
725 | return; | 609 | zone_key, |
726 | } | 610 | &(rd->key), |
727 | if (GNUNET_OK != | 611 | ®ister_error_cb, |
728 | GNUNET_IDENTITY_public_key_from_string (request->public_key, | 612 | rd, |
729 | &request->pub)) | 613 | ®ister_do_cb, |
730 | { | 614 | 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 | } | 615 | } |
745 | 616 | ||
617 | /** | ||
618 | * Generate a response containing JSON and send it to the client. | ||
619 | * | ||
620 | * @param c the connection | ||
621 | * @param body the response body | ||
622 | * @param length the body length in bytes | ||
623 | * @param code the response code | ||
624 | * @return MHD_NO on error | ||
625 | */ | ||
626 | static MHD_RESULT | ||
627 | serve_json (struct MHD_Connection *c, | ||
628 | char *body, | ||
629 | size_t length, | ||
630 | int code) | ||
631 | { | ||
632 | struct MHD_Response *response = | ||
633 | MHD_create_response_from_buffer (length, | ||
634 | body, | ||
635 | MHD_RESPMEM_PERSISTENT); | ||
636 | MHD_RESULT r = MHD_queue_response (c, code, response); | ||
637 | MHD_destroy_response (response); | ||
638 | return r; | ||
639 | } | ||
746 | 640 | ||
747 | /** | 641 | /** |
748 | * Main MHD callback for handling requests. | 642 | * Send a response back to a connected client. |
749 | * | 643 | * |
750 | * @param cls unused | 644 | * @param cls unused |
751 | * @param connection MHD connection handle | 645 | * @param connection the connection with the client |
752 | * @param url the requested url | 646 | * @param url the requested address |
753 | * @param method the HTTP method used ("GET", "PUT", etc.) | 647 | * @param method the HTTP method used |
754 | * @param version the HTTP version string ("HTTP/1.1" for version 1.1, etc.) | 648 | * @param version the protocol version (including the "HTTP/" part) |
755 | * @param upload_data the data being uploaded (excluding HEADERS, | 649 | * @param upload_data data sent with a POST request |
756 | * for a POST that fits into memory and that is encoded | 650 | * @param upload_data_size length in bytes of the POST data |
757 | * with a supported encoding, the POST data will NOT be | 651 | * @param ptr used to pass data between request handling phases |
758 | * given in upload_data and is instead available as | 652 | * @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 | */ | 653 | */ |
770 | static MHD_RESULT | 654 | static MHD_RESULT |
771 | create_response (void *cls, | 655 | create_response (void *cls, |
@@ -777,300 +661,255 @@ create_response (void *cls, | |||
777 | size_t *upload_data_size, | 661 | size_t *upload_data_size, |
778 | void **ptr) | 662 | void **ptr) |
779 | { | 663 | { |
780 | struct MHD_Response *response; | ||
781 | struct Request *request; | ||
782 | struct GNUNET_IDENTITY_PublicKey pub; | ||
783 | MHD_RESULT ret; | ||
784 | |||
785 | (void) cls; | 664 | (void) cls; |
786 | (void) version; | 665 | (void) version; |
787 | if ((0 == strcmp (method, MHD_HTTP_METHOD_GET)) || | 666 | |
788 | (0 == strcmp (method, MHD_HTTP_METHOD_HEAD))) | 667 | struct RequestData *rd = *ptr; |
789 | { | 668 | |
790 | if (0 == strcmp (url, FCFS_ZONEINFO_URL)) | 669 | 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 | { | 670 | { |
802 | request = *ptr; | 671 | /* Handle a previously suspended request */ |
803 | if (NULL == request) | 672 | if (NULL != rd) |
673 | { | ||
674 | return serve_json (rd->c, rd->body, rd->body_length, rd->code); | ||
675 | } | ||
676 | |||
677 | if (0 == strcmp ("/", url)) | ||
804 | { | 678 | { |
805 | request = GNUNET_new (struct Request); | 679 | return MHD_queue_response (connection, |
806 | request->con = connection; | 680 | MHD_HTTP_OK, |
807 | *ptr = request; | 681 | main_page->response); |
808 | request->pp = MHD_create_post_processor (connection, | 682 | } |
809 | 1024, | 683 | |
810 | &post_iterator, | 684 | if (0 == strcmp ("/search", url)) |
811 | request); | 685 | { |
812 | if (NULL == request->pp) | 686 | const char *name = MHD_lookup_connection_value (connection, |
687 | MHD_GET_ARGUMENT_KIND, | ||
688 | "name"); | ||
689 | if (NULL == name) | ||
813 | { | 690 | { |
814 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 691 | return MHD_queue_response (connection, |
815 | _ ("Failed to setup post processor for `%s'\n"), | 692 | MHD_HTTP_BAD_REQUEST, |
816 | url); | 693 | forbidden_page->response); |
817 | return MHD_NO; /* internal error */ | ||
818 | } | 694 | } |
695 | |||
696 | MHD_suspend_connection (connection); | ||
697 | rd = GNUNET_new (struct RequestData); | ||
698 | rd->c = connection; | ||
699 | rd->searching = GNUNET_NAMESTORE_records_lookup (namestore, | ||
700 | zone_key, | ||
701 | name, | ||
702 | &search_error_cb, | ||
703 | rd, | ||
704 | &search_done_cb, | ||
705 | rd); | ||
706 | *ptr = rd; | ||
819 | return MHD_YES; | 707 | return MHD_YES; |
820 | } | 708 | } |
821 | if (NULL != request->pp) | 709 | |
710 | return MHD_queue_response (connection, | ||
711 | MHD_HTTP_NOT_FOUND, | ||
712 | notfound_page->response); | ||
713 | } | ||
714 | |||
715 | if (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) | ||
716 | { | ||
717 | /* We take a shortcut here by always serving the main page: starting a | ||
718 | namestore lookup, allocating the necessary resources, waiting for the | ||
719 | lookup to complete and then discard everything just because it was a HEAD | ||
720 | and thus only the headers are significative, is an unnecessary waste of | ||
721 | resources. The handling of this method could be smarter, for example by | ||
722 | sending a proper content type header based on the endpoint, but this is | ||
723 | not a service in which HEAD requests are significant, so there's no need | ||
724 | to spend too much time here. */ | ||
725 | return MHD_queue_response (connection, | ||
726 | MHD_HTTP_OK, | ||
727 | main_page->response); | ||
728 | } | ||
729 | |||
730 | if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) | ||
731 | { | ||
732 | if (0 == strcmp ("/register", url)) | ||
822 | { | 733 | { |
823 | /* evaluate POST data */ | 734 | /* Handle a previously suspended request */ |
824 | MHD_post_process (request->pp, | 735 | if (NULL != rd && NULL != rd->body) |
825 | upload_data, | ||
826 | *upload_data_size); | ||
827 | if (0 != *upload_data_size) | ||
828 | { | 736 | { |
829 | *upload_data_size = 0; | 737 | return serve_json (rd->c, rd->body, rd->body_length, rd->code); |
830 | return MHD_YES; | ||
831 | } | 738 | } |
832 | /* done with POST data, serve response */ | 739 | |
833 | MHD_destroy_post_processor (request->pp); | 740 | 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 | { | 741 | { |
849 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 742 | rd = GNUNET_new (struct RequestData); |
850 | _ ("Domain name must not contain `.'\n")); | 743 | rd->c = connection; |
851 | request->phase = RP_FAIL; | 744 | rd->body = NULL; |
852 | return fill_s_reply ("Domain name must not contain `.', sorry.", | 745 | rd->ptr = NULL; |
853 | request, | 746 | *ptr = rd; |
854 | connection); | ||
855 | } | 747 | } |
856 | if (NULL != strchr (request->domain_name, (int) '+')) | 748 | |
749 | json_t *json = NULL; | ||
750 | enum GNUNET_JSON_PostResult result = | ||
751 | GNUNET_JSON_post_parser (32 * 1024, | ||
752 | connection, | ||
753 | &(rd->ptr), | ||
754 | upload_data, | ||
755 | upload_data_size, | ||
756 | &json); | ||
757 | |||
758 | switch (result) | ||
857 | { | 759 | { |
858 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 760 | case GNUNET_JSON_PR_CONTINUE: |
859 | _ ("Domain name must not contain `+'\n")); | 761 | /* Keep processing POST data */ |
860 | request->phase = RP_FAIL; | 762 | return MHD_YES; |
861 | return fill_s_reply ("Domain name must not contain `+', sorry.", | 763 | case GNUNET_JSON_PR_OUT_OF_MEMORY: |
862 | request, connection); | 764 | case GNUNET_JSON_PR_REQUEST_TOO_LARGE: |
765 | rd->body = make_json ("error", "true", | ||
766 | "message", _ ("unable to process submitted data"), | ||
767 | NULL); | ||
768 | rd->body_length = strlen (rd->body); | ||
769 | rd->code = MHD_HTTP_PAYLOAD_TOO_LARGE; | ||
770 | return MHD_YES; | ||
771 | case GNUNET_JSON_PR_JSON_INVALID: | ||
772 | rd->body = make_json ("error", "true", | ||
773 | "message", _ ("the submitted data is invalid"), | ||
774 | NULL); | ||
775 | rd->body_length = strlen (rd->body); | ||
776 | rd->code = MHD_HTTP_BAD_REQUEST; | ||
777 | return MHD_YES; | ||
778 | default: | ||
779 | break; | ||
863 | } | 780 | } |
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 | 781 | ||
782 | /* POST data has been read in its entirety */ | ||
908 | 783 | ||
909 | /** | 784 | const char *name = json_string_value(json_object_get(json, "name")); |
910 | * Callback called upon completion of a request. | 785 | const char *key = json_string_value(json_object_get(json, "key")); |
911 | * Decrements session reference counter. | 786 | if (NULL == name || NULL == key || 0 == strlen (name) || 0 == strlen (key)) |
912 | * | 787 | { |
913 | * @param cls not used | 788 | json_decref (json); |
914 | * @param connection connection that completed | 789 | rd->body = make_json ("error", "true", |
915 | * @param con_cls session handle | 790 | "message", _ ("invalid parameters"), |
916 | * @param toe status code | 791 | NULL); |
917 | */ | 792 | rd->body_length = strlen (rd->body); |
918 | static void | 793 | rd->code = MHD_HTTP_BAD_REQUEST; |
919 | request_completed_callback (void *cls, | 794 | return MHD_YES; |
920 | struct MHD_Connection *connection, | 795 | } |
921 | void **con_cls, | ||
922 | enum MHD_RequestTerminationCode toe) | ||
923 | { | ||
924 | struct Request *request = *con_cls; | ||
925 | 796 | ||
926 | (void) cls; | 797 | rd->register_name = strdup (name); |
927 | (void) connection; | 798 | 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 | 799 | ||
800 | json_decref (json); | ||
801 | GNUNET_JSON_post_parser_cleanup (rd->ptr); | ||
938 | 802 | ||
939 | #define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG | 803 | if (NULL != strchr (rd->register_name, '.') || |
804 | NULL != strchr (rd->register_name, '+')) | ||
805 | { | ||
806 | rd->body = make_json ("error", "true", | ||
807 | "message", _ ("invalid name"), | ||
808 | NULL); | ||
809 | rd->body_length = strlen (rd->body); | ||
810 | rd->code = MHD_HTTP_BAD_REQUEST; | ||
811 | return MHD_YES; | ||
812 | } | ||
940 | 813 | ||
814 | if (GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (rd->register_key, | ||
815 | &(rd->key))) | ||
816 | { | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
818 | _ ("Unable to parse key %s\n"), | ||
819 | rd->register_key); | ||
820 | |||
821 | rd->body = make_json ("error", "true", | ||
822 | "message", _ ("unable to parse key"), | ||
823 | NULL); | ||
824 | rd->body_length = strlen (rd->body); | ||
825 | rd->code = MHD_HTTP_INTERNAL_SERVER_ERROR; | ||
826 | return MHD_YES; | ||
827 | } | ||
941 | 828 | ||
942 | /** | 829 | MHD_suspend_connection (connection); |
943 | * Schedule tasks to run MHD server. | 830 | /* See if the requested name is free */ |
944 | */ | 831 | rd->iterating = |
945 | static void | 832 | GNUNET_NAMESTORE_zone_iteration_start (namestore, |
946 | run_httpd () | 833 | zone_key, |
947 | { | 834 | &iterate_error_cb, |
948 | fd_set rs; | 835 | rd, |
949 | fd_set ws; | 836 | &iterate_do_cb, |
950 | fd_set es; | 837 | rd, |
951 | struct GNUNET_NETWORK_FDSet *wrs; | 838 | &iterate_done_cb, |
952 | struct GNUNET_NETWORK_FDSet *wws; | 839 | rd); |
953 | struct GNUNET_NETWORK_FDSet *wes; | 840 | return MHD_YES; |
954 | int max; | 841 | } |
955 | int haveto; | ||
956 | UNSIGNED_MHD_LONG_LONG timeout; | ||
957 | struct GNUNET_TIME_Relative tv; | ||
958 | 842 | ||
959 | FD_ZERO (&rs); | 843 | return MHD_queue_response (connection, |
960 | FD_ZERO (&ws); | 844 | MHD_HTTP_FORBIDDEN, |
961 | FD_ZERO (&es); | 845 | forbidden_page->response); |
962 | wrs = GNUNET_NETWORK_fdset_create (); | 846 | } |
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 | 847 | ||
848 | return MHD_queue_response (connection, | ||
849 | MHD_HTTP_NOT_IMPLEMENTED, | ||
850 | forbidden_page->response); | ||
851 | } | ||
999 | 852 | ||
1000 | /** | 853 | /** |
1001 | * Task run whenever HTTP server operations are pending. | 854 | * Called when a request is completed. |
1002 | * | 855 | * |
1003 | * @param cls unused | 856 | * @param cls unused |
857 | * @param connection the connection | ||
858 | * @param ptr connection-specific data | ||
859 | * @param status status code | ||
1004 | */ | 860 | */ |
1005 | static void | 861 | static void |
1006 | do_httpd (void *cls) | 862 | completed_cb (void *cls, |
863 | struct MHD_Connection *connection, | ||
864 | void **ptr, | ||
865 | enum MHD_RequestTerminationCode status) | ||
1007 | { | 866 | { |
1008 | (void) cls; | 867 | (void) cls; |
1009 | httpd_task = NULL; | 868 | (void) connection; |
1010 | MHD_run (httpd); | 869 | (void) status; |
1011 | run_httpd (); | ||
1012 | } | ||
1013 | 870 | ||
871 | struct RequestData *rd = *ptr; | ||
1014 | 872 | ||
1015 | /** | 873 | 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 | { | 874 | { |
1026 | GNUNET_SCHEDULER_cancel (httpd_task); | 875 | return; |
1027 | httpd_task = NULL; | ||
1028 | } | 876 | } |
1029 | if (NULL != uzp_task) | 877 | |
878 | if (NULL == rd->body) | ||
1030 | { | 879 | { |
1031 | GNUNET_SCHEDULER_cancel (uzp_task); | 880 | GNUNET_free (rd->body); |
1032 | uzp_task = NULL; | ||
1033 | } | 881 | } |
1034 | if (NULL != ns) | 882 | |
883 | if (NULL != rd->searching) | ||
1035 | { | 884 | { |
1036 | GNUNET_NAMESTORE_disconnect (ns); | 885 | GNUNET_NAMESTORE_cancel (rd->searching); |
1037 | ns = NULL; | ||
1038 | } | 886 | } |
1039 | if (NULL != httpd) | 887 | |
888 | if (NULL != rd->register_name) | ||
1040 | { | 889 | { |
1041 | MHD_stop_daemon (httpd); | 890 | GNUNET_free (rd->register_name); |
1042 | httpd = NULL; | ||
1043 | } | 891 | } |
1044 | if (NULL != id_op) | 892 | |
893 | if (NULL != rd->register_key) | ||
1045 | { | 894 | { |
1046 | GNUNET_IDENTITY_cancel (id_op); | 895 | GNUNET_free (rd->register_key); |
1047 | id_op = NULL; | ||
1048 | } | 896 | } |
1049 | if (NULL != identity) | 897 | |
898 | if (NULL != rd->iterating) | ||
1050 | { | 899 | { |
1051 | GNUNET_IDENTITY_disconnect (identity); | 900 | GNUNET_NAMESTORE_zone_iteration_stop (rd->iterating); |
1052 | identity = NULL; | ||
1053 | } | 901 | } |
1054 | } | ||
1055 | 902 | ||
903 | GNUNET_free (rd); | ||
904 | } | ||
1056 | 905 | ||
1057 | /** | 906 | /** |
1058 | * Method called to inform about the egos of this peer. | 907 | * 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 | * | 908 | * |
1067 | * @param cls closure, NULL | 909 | * @param cls closure |
1068 | * @param ego ego handle | 910 | * @param ego the ego |
1069 | * @param ctx context for application to store data for this ego | 911 | * @param ctx application-provided data for the ego |
1070 | * (during the lifetime of this process, initially NULL) | 912 | * @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 | */ | 913 | */ |
1075 | static void | 914 | static void |
1076 | identity_cb (void *cls, | 915 | identity_cb (void *cls, |
@@ -1078,15 +917,14 @@ identity_cb (void *cls, | |||
1078 | void **ctx, | 917 | void **ctx, |
1079 | const char *name) | 918 | const char *name) |
1080 | { | 919 | { |
1081 | int options; | ||
1082 | |||
1083 | (void) cls; | 920 | (void) cls; |
1084 | (void) ctx; | 921 | (void) ctx; |
1085 | if (NULL == name) | 922 | |
1086 | return; | 923 | if (NULL == name || 0 != strcmp (name, zone)) |
1087 | if (0 != strcmp (name, | 924 | { |
1088 | zone)) | ||
1089 | return; | 925 | return; |
926 | } | ||
927 | |||
1090 | if (NULL == ego) | 928 | if (NULL == ego) |
1091 | { | 929 | { |
1092 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 930 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
@@ -1094,30 +932,24 @@ identity_cb (void *cls, | |||
1094 | GNUNET_SCHEDULER_shutdown (); | 932 | GNUNET_SCHEDULER_shutdown (); |
1095 | return; | 933 | return; |
1096 | } | 934 | } |
1097 | fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego); | ||
1098 | 935 | ||
1099 | options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME; | 936 | zone_key = GNUNET_IDENTITY_ego_get_private_key (ego); |
937 | |||
938 | int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME; | ||
1100 | do | 939 | do |
1101 | { | 940 | { |
1102 | httpd = MHD_start_daemon (options, | 941 | httpd = MHD_start_daemon (flags, |
1103 | (uint16_t) port, | 942 | (uint16_t) port, |
1104 | NULL, NULL, | 943 | NULL, NULL, |
1105 | &create_response, NULL, | 944 | &create_response, NULL, |
1106 | MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, | 945 | MHD_OPTION_CONNECTION_LIMIT, 128, |
1107 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned | 946 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1, |
1108 | int) 1, | 947 | MHD_OPTION_CONNECTION_TIMEOUT, 4 * 1024, |
1109 | MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, | 948 | 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); | 949 | MHD_OPTION_END); |
1116 | if (MHD_USE_DEBUG == options) | 950 | flags = MHD_USE_DEBUG; |
1117 | break; | 951 | } while (NULL == httpd && flags != MHD_USE_DEBUG); |
1118 | options = MHD_USE_DEBUG; | 952 | |
1119 | } | ||
1120 | while (NULL == httpd); | ||
1121 | if (NULL == httpd) | 953 | if (NULL == httpd) |
1122 | { | 954 | { |
1123 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 955 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
@@ -1125,105 +957,158 @@ identity_cb (void *cls, | |||
1125 | GNUNET_SCHEDULER_shutdown (); | 957 | GNUNET_SCHEDULER_shutdown (); |
1126 | return; | 958 | return; |
1127 | } | 959 | } |
960 | |||
1128 | run_httpd (); | 961 | run_httpd (); |
1129 | } | 962 | } |
1130 | 963 | ||
964 | /** | ||
965 | * Open a file on disk and generate a response object for it. | ||
966 | * | ||
967 | * @param name name of the file to open | ||
968 | * @param basedir directory where the file is located | ||
969 | * @return #GNUNET_SYSERR on error | ||
970 | */ | ||
971 | static struct StaticPage * | ||
972 | open_static_page (const char *name, const char *basedir) | ||
973 | { | ||
974 | char *fullname = NULL; | ||
975 | GNUNET_asprintf (&fullname, "%s/fcfsd-%s", basedir, name); | ||
976 | |||
977 | struct GNUNET_DISK_FileHandle *f = | ||
978 | GNUNET_DISK_file_open (fullname, | ||
979 | GNUNET_DISK_OPEN_READ, | ||
980 | GNUNET_DISK_PERM_NONE); | ||
981 | GNUNET_free (fullname); | ||
982 | |||
983 | if (NULL == f) | ||
984 | { | ||
985 | return NULL; | ||
986 | } | ||
987 | |||
988 | off_t size = 0; | ||
989 | if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size)) | ||
990 | { | ||
991 | GNUNET_DISK_file_close (f); | ||
992 | return NULL; | ||
993 | } | ||
994 | |||
995 | struct MHD_Response *response = | ||
996 | MHD_create_response_from_fd64 (size, | ||
997 | f->fd); | ||
998 | |||
999 | if (NULL == response) | ||
1000 | { | ||
1001 | GNUNET_DISK_file_close (f); | ||
1002 | return NULL; | ||
1003 | } | ||
1004 | |||
1005 | struct StaticPage *page = GNUNET_new (struct StaticPage); | ||
1006 | page->handle = f; | ||
1007 | page->size = (uint64_t) size; | ||
1008 | page->response = response; | ||
1009 | return page; | ||
1010 | } | ||
1131 | 1011 | ||
1132 | /** | 1012 | /** |
1133 | * Main function that will be run. | 1013 | * Called after the service is up. |
1134 | * | 1014 | * |
1135 | * @param cls closure | 1015 | * @param cls closure |
1136 | * @param args remaining command-line arguments | 1016 | * @param args remaining command line arguments |
1137 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | 1017 | * @param cfgfile name of the configuration file |
1138 | * @param cfg configuration | 1018 | * @param cfg the service configuration |
1139 | */ | 1019 | */ |
1140 | static void | 1020 | static void |
1141 | run (void *cls, | 1021 | run_service (void *cls, |
1142 | char *const *args, | 1022 | char *const *args, |
1143 | const char *cfgfile, | 1023 | const char *cfgfile, |
1144 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 1024 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
1145 | { | 1025 | { |
1146 | (void) cls; | 1026 | (void) cls; |
1147 | (void) args; | 1027 | (void) args; |
1148 | (void) cfgfile; | 1028 | (void) cfgfile; |
1149 | if (GNUNET_OK != | 1029 | |
1150 | GNUNET_CONFIGURATION_get_value_number (cfg, | 1030 | GNUNET_log_setup ("fcfsd", "WARNING", NULL); |
1151 | "fcfsd", | 1031 | |
1152 | "HTTPPORT", | 1032 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, |
1153 | &port)) | 1033 | "fcfsd", |
1034 | "HTTPPORT", | ||
1035 | &port)) | ||
1154 | { | 1036 | { |
1155 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | 1037 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1156 | "fcfsd", "HTTPPORT"); | 1038 | _ ("No port specified, using default value\n")); |
1157 | return; | ||
1158 | } | 1039 | } |
1159 | ns = GNUNET_NAMESTORE_connect (cfg); | 1040 | |
1160 | if (NULL == ns) | 1041 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); |
1042 | |||
1043 | namestore = GNUNET_NAMESTORE_connect (cfg); | ||
1044 | if (NULL == namestore) | ||
1161 | { | 1045 | { |
1162 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1046 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1163 | _ ("Failed to connect to namestore\n")); | 1047 | _ ("Failed to connect to namestore\n")); |
1048 | GNUNET_SCHEDULER_shutdown (); | ||
1164 | return; | 1049 | return; |
1165 | } | 1050 | } |
1166 | identity = GNUNET_IDENTITY_connect (cfg, | 1051 | |
1167 | &identity_cb, | 1052 | identity = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL); |
1168 | NULL); | ||
1169 | if (NULL == identity) | 1053 | if (NULL == identity) |
1170 | { | 1054 | { |
1171 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1055 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1172 | _ ("Failed to connect to identity\n")); | 1056 | _ ("Failed to connect to identity\n")); |
1057 | GNUNET_SCHEDULER_shutdown (); | ||
1173 | return; | 1058 | return; |
1174 | } | 1059 | } |
1175 | uzp_task = GNUNET_SCHEDULER_add_now (&update_zoneinfo_page, | ||
1176 | NULL); | ||
1177 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, | ||
1178 | NULL); | ||
1179 | } | ||
1180 | 1060 | ||
1061 | char *basedir = NULL; | ||
1062 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
1063 | "fcfsd", | ||
1064 | "HTMLDIR", | ||
1065 | &basedir)) | ||
1066 | { | ||
1067 | basedir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); | ||
1068 | } | ||
1069 | |||
1070 | main_page = open_static_page ("index.html", basedir); | ||
1071 | notfound_page = open_static_page ("notfound.html", basedir); | ||
1072 | forbidden_page = open_static_page ("forbidden.html", basedir); | ||
1073 | |||
1074 | GNUNET_free (basedir); | ||
1075 | |||
1076 | if (NULL == main_page || NULL == notfound_page || NULL == forbidden_page) | ||
1077 | { | ||
1078 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1079 | _ ("Unable to set up the daemon\n")); | ||
1080 | GNUNET_SCHEDULER_shutdown (); | ||
1081 | return; | ||
1082 | } | ||
1083 | } | ||
1181 | 1084 | ||
1182 | /** | 1085 | /** |
1183 | * The main function for the fcfs daemon. | 1086 | * The main function of the fcfs daemon. |
1184 | * | 1087 | * |
1185 | * @param argc number of arguments from the command line | 1088 | * @param argc number of arguments from the command line |
1186 | * @param argv command line arguments | 1089 | * @parsm argv the command line argumens |
1187 | * @return 0 ok, 1 on error | 1090 | * @return 0 successful exit, a different value otherwise |
1188 | */ | 1091 | */ |
1189 | int | 1092 | int |
1190 | main (int argc, | 1093 | main (int argc, char *const *argv) |
1191 | char *const *argv) | ||
1192 | { | 1094 | { |
1193 | struct GNUNET_GETOPT_CommandLineOption options[] = { | 1095 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
1194 | GNUNET_GETOPT_option_mandatory | 1096 | GNUNET_GETOPT_option_mandatory |
1195 | (GNUNET_GETOPT_option_string ('z', | 1097 | (GNUNET_GETOPT_option_string ('z', |
1196 | "zone", | 1098 | "zone", |
1197 | "EGO", | 1099 | "EGO", |
1198 | gettext_noop ( | 1100 | gettext_noop ("name of the zone managed by FCFSD"), |
1199 | "name of the zone that is to be managed by FCFSD"), | 1101 | &zone)), |
1200 | &zone)), | ||
1201 | GNUNET_GETOPT_OPTION_END | 1102 | GNUNET_GETOPT_OPTION_END |
1202 | }; | 1103 | }; |
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 | 1104 | ||
1228 | 1105 | return ((GNUNET_OK == GNUNET_PROGRAM_run (argc, | |
1229 | /* end of gnunet-namestore-fcfsd.c */ | 1106 | argv, |
1107 | "gnunet-namestore-fcfsd", | ||
1108 | _ ("GNU Name System First-Come-First-Served name registration service"), | ||
1109 | options, | ||
1110 | &run_service, | ||
1111 | NULL)) ? | ||
1112 | 0 : | ||
1113 | 1); | ||
1114 | } | ||