diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-03-03 22:04:41 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-03-03 22:04:41 +0000 |
commit | 99fc1398c292e6e3069f7743a1d8d8f382f4c879 (patch) | |
tree | 80e6c455c21c9e4e3f908a46a0c3249e53efea3b /src/gns/gnunet-gns-fcfsd.c | |
parent | 2ed8a19a0e8da985fa170906f2ea9026a2c69afa (diff) | |
download | gnunet-99fc1398c292e6e3069f7743a1d8d8f382f4c879.tar.gz gnunet-99fc1398c292e6e3069f7743a1d8d8f382f4c879.zip |
-starting with a simple domain registration WWW service
Diffstat (limited to 'src/gns/gnunet-gns-fcfsd.c')
-rw-r--r-- | src/gns/gnunet-gns-fcfsd.c | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/src/gns/gnunet-gns-fcfsd.c b/src/gns/gnunet-gns-fcfsd.c new file mode 100644 index 000000000..e7ce0161b --- /dev/null +++ b/src/gns/gnunet-gns-fcfsd.c | |||
@@ -0,0 +1,742 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2012 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file gnunet-gns-fcfsd.c | ||
22 | * @brief HTTP daemon that offers first-come-first-serve GNS domain registration | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * TODO: | ||
26 | * - the code currently contains a 'race' between checking that the | ||
27 | * domain name is available and allocating it to the new public key | ||
28 | * (should this race be solved by namestore or by fcfsd?) | ||
29 | */ | ||
30 | #include "platform.h" | ||
31 | #include <gnunet_util_lib.h> | ||
32 | #include <microhttpd.h> | ||
33 | #include <gnunet_namestore_service.h> | ||
34 | |||
35 | /** | ||
36 | * Invalid method page. | ||
37 | */ | ||
38 | #define METHOD_ERROR "<html><head><title>Illegal request</title></head><body>Go away.</body></html>" | ||
39 | |||
40 | /** | ||
41 | * Front page. (/) | ||
42 | */ | ||
43 | #define MAIN_PAGE "<html><head><title>Welcome</title></head><body><form action=\"/S\" method=\"post\">What is your desired domain name? <input type=\"text\" name=\"domain\" /> <p> What is your public key? <input type=\"text\" name=\"pkey\" /> <input type=\"submit\" value=\"Next\" /></body></html>" | ||
44 | |||
45 | /** | ||
46 | * Second page (/S) | ||
47 | */ | ||
48 | #define SUBMIT_PAGE "<html><head><title>%s</title></head><body>%s</body></html>" | ||
49 | |||
50 | /** | ||
51 | * Mime type for HTML pages. | ||
52 | */ | ||
53 | #define MIME_HTML "text/html" | ||
54 | |||
55 | /** | ||
56 | * Name of our cookie. | ||
57 | */ | ||
58 | #define COOKIE_NAME "gns-fcfs" | ||
59 | |||
60 | |||
61 | enum Phase | ||
62 | { | ||
63 | RP_START = 0, | ||
64 | RP_LOOKUP, | ||
65 | RP_PUT, | ||
66 | RP_SUCCESS, | ||
67 | RP_FAIL | ||
68 | }; | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Data kept per request. | ||
73 | */ | ||
74 | struct Request | ||
75 | { | ||
76 | |||
77 | /** | ||
78 | * Associated session. | ||
79 | */ | ||
80 | struct Session *session; | ||
81 | |||
82 | /** | ||
83 | * Post processor handling form data (IF this is | ||
84 | * a POST request). | ||
85 | */ | ||
86 | struct MHD_PostProcessor *pp; | ||
87 | |||
88 | /** | ||
89 | * URL to serve in response to this POST (if this request | ||
90 | * was a 'POST') | ||
91 | */ | ||
92 | const char *post_url; | ||
93 | |||
94 | /** | ||
95 | * Active request with the namestore. | ||
96 | */ | ||
97 | struct GNUNET_NAMESTORE_QueueEntry *qe; | ||
98 | |||
99 | /** | ||
100 | * Current processing phase. | ||
101 | */ | ||
102 | enum Phase phase; | ||
103 | |||
104 | /** | ||
105 | * Domain name submitted via form. | ||
106 | */ | ||
107 | char domain_name[64]; | ||
108 | |||
109 | /** | ||
110 | * Public key submitted via form. | ||
111 | */ | ||
112 | char public_key[1024]; | ||
113 | |||
114 | }; | ||
115 | |||
116 | |||
117 | /** | ||
118 | * MHD deamon reference. | ||
119 | */ | ||
120 | static struct MHD_Daemon *httpd; | ||
121 | |||
122 | /** | ||
123 | * Main HTTP task. | ||
124 | */ | ||
125 | static GNUNET_SCHEDULER_TaskIdentifier httpd_task; | ||
126 | |||
127 | /** | ||
128 | * Handle to the namestore. | ||
129 | */ | ||
130 | static struct GNUNET_NAMESTORE_Handle *ns; | ||
131 | |||
132 | /** | ||
133 | * Hash of the public key of the fcfsd zone. | ||
134 | */ | ||
135 | static GNUNET_HashCode fcfsd_zone; | ||
136 | |||
137 | /** | ||
138 | * Private key for the fcfsd zone. | ||
139 | */ | ||
140 | static struct GNUNET_CRYPTO_RsaPrivateKey *fcfs_zone_pkey; | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Handler that returns a simple static HTTP page. | ||
145 | * | ||
146 | * @param connection connection to use | ||
147 | * @return MHD_YES on success | ||
148 | */ | ||
149 | static int | ||
150 | serve_main_page (struct MHD_Connection *connection) | ||
151 | { | ||
152 | int ret; | ||
153 | struct MHD_Response *response; | ||
154 | |||
155 | /* return static form */ | ||
156 | response = MHD_create_response_from_buffer (strlen (MAIN_PAGE), | ||
157 | (void *) MAIN_PAGE, | ||
158 | MHD_RESPMEM_PERSISTENT); | ||
159 | MHD_add_response_header (response, | ||
160 | MHD_HTTP_HEADER_CONTENT_ENCODING, | ||
161 | MIME_HTML); | ||
162 | ret = MHD_queue_response (connection, | ||
163 | MHD_HTTP_OK, | ||
164 | response); | ||
165 | MHD_destroy_response (response); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Send the 'SUBMIT_PAGE'. | ||
172 | * | ||
173 | * @param info information string to send to the user | ||
174 | * @param request request information | ||
175 | * @param connection connection to use | ||
176 | */ | ||
177 | static int | ||
178 | fill_s_reply (const char *info, | ||
179 | struct Request *request, | ||
180 | struct MHD_Connection *connection) | ||
181 | { | ||
182 | int ret; | ||
183 | char *reply; | ||
184 | struct MHD_Response *response; | ||
185 | |||
186 | GNUNET_asprintf (&reply, | ||
187 | SUBMIT_PAGE, | ||
188 | info, | ||
189 | info); | ||
190 | /* return static form */ | ||
191 | response = MHD_create_response_from_buffer (strlen (reply), | ||
192 | (void *) reply, | ||
193 | MHD_RESPMEM_MUST_FREE); | ||
194 | MHD_add_response_header (response, | ||
195 | MHD_HTTP_HEADER_CONTENT_ENCODING, | ||
196 | MIME_HTML); | ||
197 | ret = MHD_queue_response (connection, | ||
198 | MHD_HTTP_OK, | ||
199 | response); | ||
200 | MHD_destroy_response (response); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | |||
205 | /** | ||
206 | * Iterator over key-value pairs where the value | ||
207 | * maybe made available in increments and/or may | ||
208 | * not be zero-terminated. Used for processing | ||
209 | * POST data. | ||
210 | * | ||
211 | * @param cls user-specified closure | ||
212 | * @param kind type of the value | ||
213 | * @param key 0-terminated key for the value | ||
214 | * @param filename name of the uploaded file, NULL if not known | ||
215 | * @param content_type mime-type of the data, NULL if not known | ||
216 | * @param transfer_encoding encoding of the data, NULL if not known | ||
217 | * @param data pointer to size bytes of data at the | ||
218 | * specified offset | ||
219 | * @param off offset of data in the overall value | ||
220 | * @param size number of bytes in data available | ||
221 | * @return MHD_YES to continue iterating, | ||
222 | * MHD_NO to abort the iteration | ||
223 | */ | ||
224 | static int | ||
225 | post_iterator (void *cls, | ||
226 | enum MHD_ValueKind kind, | ||
227 | const char *key, | ||
228 | const char *filename, | ||
229 | const char *content_type, | ||
230 | const char *transfer_encoding, | ||
231 | const char *data, uint64_t off, size_t size) | ||
232 | { | ||
233 | struct Request *request = cls; | ||
234 | |||
235 | if (0 == strcmp ("domain", key)) | ||
236 | { | ||
237 | if (size + off > sizeof(request->domain_name)) | ||
238 | size = sizeof (request->domain_name) - off; | ||
239 | memcpy (&request->domain_name[off], | ||
240 | data, | ||
241 | size); | ||
242 | if (size + off < sizeof (request->domain_name)) | ||
243 | request->domain_name[size+off] = '\0'; | ||
244 | return MHD_YES; | ||
245 | } | ||
246 | if (0 == strcmp ("pkey", key)) | ||
247 | { | ||
248 | if (size + off > sizeof(request->public_key)) | ||
249 | size = sizeof (request->public_key) - off; | ||
250 | memcpy (&request->public_key[off], | ||
251 | data, | ||
252 | size); | ||
253 | if (size + off < sizeof (request->public_key)) | ||
254 | request->public_key[size+off] = '\0'; | ||
255 | return MHD_YES; | ||
256 | } | ||
257 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
258 | "Unsupported form value `%s'\n", key); | ||
259 | return MHD_YES; | ||
260 | } | ||
261 | |||
262 | |||
263 | /** | ||
264 | * Task run whenever HTTP server operations are pending. | ||
265 | * | ||
266 | * @param cls unused | ||
267 | * @param tc scheduler context | ||
268 | */ | ||
269 | static void | ||
270 | do_httpd (void *cls, | ||
271 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
272 | |||
273 | |||
274 | /** | ||
275 | * Schedule task to run MHD server now. | ||
276 | */ | ||
277 | static void | ||
278 | run_httpd_now () | ||
279 | { | ||
280 | if (GNUNET_SCHEDULER_NO_TASK != httpd_task) | ||
281 | { | ||
282 | GNUNET_SCHEDULER_cancel (httpd_task); | ||
283 | httpd_task = GNUNET_SCHEDULER_NO_TASK; | ||
284 | } | ||
285 | httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL); | ||
286 | } | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Continuation called to notify client about result of the | ||
291 | * operation. | ||
292 | * | ||
293 | * @param cls closure | ||
294 | * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) | ||
295 | * GNUNET_NO if content was already there | ||
296 | * GNUNET_YES (or other positive value) on success | ||
297 | * @param emsg NULL on success, otherwise an error message | ||
298 | */ | ||
299 | static void | ||
300 | put_continuation (void *cls, | ||
301 | int32_t success, | ||
302 | const char *emsg) | ||
303 | { | ||
304 | struct Request *request = cls; | ||
305 | |||
306 | request->qe = NULL; | ||
307 | if (0 >= success) | ||
308 | { | ||
309 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
310 | _("Failed to create record for domain `%s': %s\n"), | ||
311 | request->domain_name, | ||
312 | emsg); | ||
313 | request->phase = RP_FAIL; | ||
314 | } | ||
315 | else | ||
316 | request->phase = RP_SUCCESS; | ||
317 | run_httpd_now (); | ||
318 | } | ||
319 | |||
320 | |||
321 | /** | ||
322 | * Process a record that was stored in the namestore. | ||
323 | * | ||
324 | * @param cls closure | ||
325 | * @param zone_key public key of the zone | ||
326 | * @param expire when does the corresponding block in the DHT expire (until | ||
327 | * when should we never do a DHT lookup for the same name again)?; | ||
328 | * GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore, | ||
329 | * or the expiration time of the block in the namestore (even if there are zero | ||
330 | * records matching the desired record type) | ||
331 | * @param name name that is being mapped (at most 255 characters long) | ||
332 | * @param rd_count number of entries in 'rd' array | ||
333 | * @param rd array of records with data to store | ||
334 | * @param signature signature of the record block, NULL if signature is unavailable (i.e. | ||
335 | * because the user queried for a particular record type only) | ||
336 | */ | ||
337 | static void | ||
338 | lookup_result_processor (void *cls, | ||
339 | const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, | ||
340 | struct GNUNET_TIME_Absolute expire, | ||
341 | const char *name, | ||
342 | unsigned int rd_len, | ||
343 | const struct GNUNET_NAMESTORE_RecordData *rd, | ||
344 | const struct GNUNET_CRYPTO_RsaSignature *signature) | ||
345 | { | ||
346 | struct Request *request = cls; | ||
347 | struct GNUNET_NAMESTORE_RecordData r; | ||
348 | |||
349 | request->qe = NULL; | ||
350 | if (0 != rd_len) | ||
351 | { | ||
352 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
353 | _("Found %u existing records for domain `%s'\n"), | ||
354 | rd_len, | ||
355 | request->domain_name); | ||
356 | request->phase = RP_FAIL; | ||
357 | run_httpd_now (); | ||
358 | return; | ||
359 | } | ||
360 | r.data = "binary public key"; | ||
361 | r.expiration = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
362 | r.data_size = sizeof ("binary public key"); | ||
363 | r.record_type = htonl (GNUNET_GNS_TYPE_PKEY); | ||
364 | r.flags = htonl (GNUNET_NAMESTORE_RF_AUTHORITY); | ||
365 | request->qe = GNUNET_NAMESTORE_record_create (ns, | ||
366 | fcfs_zone_pkey, | ||
367 | request->domain_name, | ||
368 | &r, | ||
369 | &put_continuation, | ||
370 | request); | ||
371 | } | ||
372 | |||
373 | |||
374 | /** | ||
375 | * Main MHD callback for handling requests. | ||
376 | * | ||
377 | * | ||
378 | * @param cls argument given together with the function | ||
379 | * pointer when the handler was registered with MHD | ||
380 | * @param url the requested url | ||
381 | * @param method the HTTP method used ("GET", "PUT", etc.) | ||
382 | * @param version the HTTP version string (i.e. "HTTP/1.1") | ||
383 | * @param upload_data the data being uploaded (excluding HEADERS, | ||
384 | * for a POST that fits into memory and that is encoded | ||
385 | * with a supported encoding, the POST data will NOT be | ||
386 | * given in upload_data and is instead available as | ||
387 | * part of MHD_get_connection_values; very large POST | ||
388 | * data *will* be made available incrementally in | ||
389 | * upload_data) | ||
390 | * @param upload_data_size set initially to the size of the | ||
391 | * upload_data provided; the method must update this | ||
392 | * value to the number of bytes NOT processed; | ||
393 | * @param con_cls pointer that the callback can set to some | ||
394 | * address and that will be preserved by MHD for future | ||
395 | * calls for this request; since the access handler may | ||
396 | * be called many times (i.e., for a PUT/POST operation | ||
397 | * with plenty of upload data) this allows the application | ||
398 | * to easily associate some request-specific state. | ||
399 | * If necessary, this state can be cleaned up in the | ||
400 | * global "MHD_RequestCompleted" callback (which | ||
401 | * can be set with the MHD_OPTION_NOTIFY_COMPLETED). | ||
402 | * Initially, <tt>*con_cls</tt> will be NULL. | ||
403 | * @return MHS_YES if the connection was handled successfully, | ||
404 | * MHS_NO if the socket must be closed due to a serios | ||
405 | * error while handling the request | ||
406 | */ | ||
407 | static int | ||
408 | create_response (void *cls, | ||
409 | struct MHD_Connection *connection, | ||
410 | const char *url, | ||
411 | const char *method, | ||
412 | const char *version, | ||
413 | const char *upload_data, | ||
414 | size_t *upload_data_size, | ||
415 | void **ptr) | ||
416 | { | ||
417 | struct MHD_Response *response; | ||
418 | struct Request *request; | ||
419 | int ret; | ||
420 | |||
421 | if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) || | ||
422 | (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) ) | ||
423 | { | ||
424 | ret = serve_main_page (connection); | ||
425 | if (ret != MHD_YES) | ||
426 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
427 | _("Failed to create page for `%s'\n"), | ||
428 | url); | ||
429 | return ret; | ||
430 | } | ||
431 | if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) | ||
432 | { | ||
433 | request = *ptr; | ||
434 | if (NULL == request) | ||
435 | { | ||
436 | request = GNUNET_malloc (sizeof (struct Request)); | ||
437 | *ptr = request; | ||
438 | request->pp = MHD_create_post_processor (connection, 1024, | ||
439 | &post_iterator, request); | ||
440 | if (NULL == request->pp) | ||
441 | { | ||
442 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
443 | _("Failed to setup post processor for `%s'\n"), | ||
444 | url); | ||
445 | return MHD_NO; /* internal error */ | ||
446 | } | ||
447 | return MHD_YES; | ||
448 | } | ||
449 | if (NULL != request->pp) | ||
450 | { | ||
451 | /* evaluate POST data */ | ||
452 | MHD_post_process (request->pp, | ||
453 | upload_data, | ||
454 | *upload_data_size); | ||
455 | if (0 != *upload_data_size) | ||
456 | { | ||
457 | *upload_data_size = 0; | ||
458 | return MHD_YES; | ||
459 | } | ||
460 | /* done with POST data, serve response */ | ||
461 | MHD_destroy_post_processor (request->pp); | ||
462 | request->pp = NULL; | ||
463 | } | ||
464 | if (strlen (request->public_key) != 2) | ||
465 | { | ||
466 | /* parse error */ | ||
467 | return fill_s_reply ("Failed to parse given public key", | ||
468 | request, connection); | ||
469 | } | ||
470 | fprintf (stderr, "Now in phase %d\n", request->phase); | ||
471 | switch (request->phase) | ||
472 | { | ||
473 | case RP_START: | ||
474 | request->phase = RP_LOOKUP; | ||
475 | request->qe = GNUNET_NAMESTORE_lookup_record (ns, | ||
476 | &fcfsd_zone, | ||
477 | request->domain_name, | ||
478 | GNUNET_GNS_TYPE_PKEY, | ||
479 | &lookup_result_processor, | ||
480 | request); | ||
481 | break; | ||
482 | case RP_LOOKUP: | ||
483 | break; | ||
484 | case RP_PUT: | ||
485 | break; | ||
486 | case RP_FAIL: | ||
487 | return fill_s_reply ("Request failed, sorry.", | ||
488 | request, connection); | ||
489 | case RP_SUCCESS: | ||
490 | return fill_s_reply ("Success.", | ||
491 | request, connection); | ||
492 | default: | ||
493 | GNUNET_break (0); | ||
494 | return MHD_NO; | ||
495 | } | ||
496 | return MHD_YES; /* will have a reply later... */ | ||
497 | } | ||
498 | /* unsupported HTTP method */ | ||
499 | response = MHD_create_response_from_buffer (strlen (METHOD_ERROR), | ||
500 | (void *) METHOD_ERROR, | ||
501 | MHD_RESPMEM_PERSISTENT); | ||
502 | ret = MHD_queue_response (connection, | ||
503 | MHD_HTTP_METHOD_NOT_ACCEPTABLE, | ||
504 | response); | ||
505 | MHD_destroy_response (response); | ||
506 | return ret; | ||
507 | } | ||
508 | |||
509 | |||
510 | /** | ||
511 | * Callback called upon completion of a request. | ||
512 | * Decrements session reference counter. | ||
513 | * | ||
514 | * @param cls not used | ||
515 | * @param connection connection that completed | ||
516 | * @param con_cls session handle | ||
517 | * @param toe status code | ||
518 | */ | ||
519 | static void | ||
520 | request_completed_callback (void *cls, | ||
521 | struct MHD_Connection *connection, | ||
522 | void **con_cls, | ||
523 | enum MHD_RequestTerminationCode toe) | ||
524 | { | ||
525 | struct Request *request = *con_cls; | ||
526 | |||
527 | if (NULL == request) | ||
528 | return; | ||
529 | if (NULL != request->pp) | ||
530 | MHD_destroy_post_processor (request->pp); | ||
531 | if (NULL != request->qe) | ||
532 | GNUNET_NAMESTORE_cancel (request->qe); | ||
533 | GNUNET_free (request); | ||
534 | } | ||
535 | |||
536 | |||
537 | /** | ||
538 | * Schedule tasks to run MHD server. | ||
539 | */ | ||
540 | static void | ||
541 | run_httpd () | ||
542 | { | ||
543 | fd_set rs; | ||
544 | fd_set ws; | ||
545 | fd_set es; | ||
546 | struct GNUNET_NETWORK_FDSet *wrs; | ||
547 | struct GNUNET_NETWORK_FDSet *wws; | ||
548 | struct GNUNET_NETWORK_FDSet *wes; | ||
549 | int max; | ||
550 | int haveto; | ||
551 | unsigned MHD_LONG_LONG timeout; | ||
552 | struct GNUNET_TIME_Relative tv; | ||
553 | |||
554 | FD_ZERO (&rs); | ||
555 | FD_ZERO (&ws); | ||
556 | FD_ZERO (&es); | ||
557 | wrs = GNUNET_NETWORK_fdset_create (); | ||
558 | wes = GNUNET_NETWORK_fdset_create (); | ||
559 | wws = GNUNET_NETWORK_fdset_create (); | ||
560 | max = -1; | ||
561 | GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); | ||
562 | haveto = MHD_get_timeout (httpd, &timeout); | ||
563 | if (haveto == MHD_YES) | ||
564 | tv.rel_value = (uint64_t) timeout; | ||
565 | else | ||
566 | tv = GNUNET_TIME_UNIT_FOREVER_REL; | ||
567 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | ||
568 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | ||
569 | GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); | ||
570 | httpd_task = | ||
571 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
572 | GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws, | ||
573 | &do_httpd, NULL); | ||
574 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
575 | GNUNET_NETWORK_fdset_destroy (wws); | ||
576 | GNUNET_NETWORK_fdset_destroy (wes); | ||
577 | } | ||
578 | |||
579 | |||
580 | /** | ||
581 | * Task run whenever HTTP server operations are pending. | ||
582 | * | ||
583 | * @param cls unused | ||
584 | * @param tc scheduler context | ||
585 | */ | ||
586 | static void | ||
587 | do_httpd (void *cls, | ||
588 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
589 | { | ||
590 | httpd_task = GNUNET_SCHEDULER_NO_TASK; | ||
591 | MHD_run (httpd); | ||
592 | run_httpd (); | ||
593 | } | ||
594 | |||
595 | |||
596 | /** | ||
597 | * Task run on shutdown. Cleans up everything. | ||
598 | * | ||
599 | * @param cls unused | ||
600 | * @param tc scheduler context | ||
601 | */ | ||
602 | static void | ||
603 | do_shutdown (void *cls, | ||
604 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
605 | { | ||
606 | if (GNUNET_SCHEDULER_NO_TASK != httpd_task) | ||
607 | { | ||
608 | GNUNET_SCHEDULER_cancel (httpd_task); | ||
609 | httpd_task = GNUNET_SCHEDULER_NO_TASK; | ||
610 | } | ||
611 | if (NULL != ns) | ||
612 | { | ||
613 | GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); | ||
614 | ns = NULL; | ||
615 | } | ||
616 | if (NULL != httpd) | ||
617 | { | ||
618 | MHD_stop_daemon (httpd); | ||
619 | httpd = NULL; | ||
620 | } | ||
621 | if (NULL != fcfs_zone_pkey) | ||
622 | { | ||
623 | GNUNET_CRYPTO_rsa_key_free (fcfs_zone_pkey); | ||
624 | fcfs_zone_pkey = NULL; | ||
625 | } | ||
626 | } | ||
627 | |||
628 | |||
629 | /** | ||
630 | * Main function that will be run. | ||
631 | * | ||
632 | * @param cls closure | ||
633 | * @param args remaining command-line arguments | ||
634 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
635 | * @param cfg configuration | ||
636 | */ | ||
637 | static void | ||
638 | run (void *cls, char *const *args, const char *cfgfile, | ||
639 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
640 | { | ||
641 | char *keyfile; | ||
642 | unsigned long long port; | ||
643 | struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub; | ||
644 | |||
645 | if (GNUNET_OK != | ||
646 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
647 | "fcfsd", | ||
648 | "HTTPPORT", | ||
649 | &port)) | ||
650 | { | ||
651 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
652 | _("Option `%s' not specified in configuration section `%s'\n"), | ||
653 | "HTTPPORT", | ||
654 | "fcfsd"); | ||
655 | return; | ||
656 | } | ||
657 | if (GNUNET_OK != | ||
658 | GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
659 | "fcfsd", | ||
660 | "ZONEKEY", | ||
661 | &keyfile)) | ||
662 | { | ||
663 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
664 | _("Option `%s' not specified in configuration section `%s'\n"), | ||
665 | "ZONEKEY", | ||
666 | "fcfsd"); | ||
667 | return; | ||
668 | } | ||
669 | fcfs_zone_pkey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); | ||
670 | GNUNET_free (keyfile); | ||
671 | if (NULL == fcfs_zone_pkey) | ||
672 | { | ||
673 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
674 | _("Failed to read or create private zone key\n")); | ||
675 | return; | ||
676 | } | ||
677 | GNUNET_CRYPTO_rsa_key_get_public (fcfs_zone_pkey, | ||
678 | &pub); | ||
679 | GNUNET_CRYPTO_hash (&pub, sizeof (pub), &fcfsd_zone); | ||
680 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
681 | _("Managing `%s' as FCFS zone on port %llu\n"), | ||
682 | GNUNET_h2s_full (&fcfsd_zone), | ||
683 | port); | ||
684 | ns = GNUNET_NAMESTORE_connect (cfg); | ||
685 | if (NULL == ns) | ||
686 | { | ||
687 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
688 | _("Failed to connect to namestore\n")); | ||
689 | return; | ||
690 | } | ||
691 | httpd = MHD_start_daemon (MHD_USE_DEBUG, | ||
692 | (uint16_t) port, | ||
693 | NULL, NULL, | ||
694 | &create_response, NULL, | ||
695 | MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, | ||
696 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, | ||
697 | MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, | ||
698 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024), | ||
699 | MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL, | ||
700 | MHD_OPTION_END); | ||
701 | if (NULL == httpd) | ||
702 | { | ||
703 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
704 | _("Failed to start HTTP server\n")); | ||
705 | GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO); | ||
706 | ns = NULL; | ||
707 | return; | ||
708 | } | ||
709 | run_httpd (); | ||
710 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
711 | &do_shutdown, NULL); | ||
712 | } | ||
713 | |||
714 | |||
715 | /** | ||
716 | * The main function for the fcfs daemon. | ||
717 | * | ||
718 | * @param argc number of arguments from the command line | ||
719 | * @param argv command line arguments | ||
720 | * @return 0 ok, 1 on error | ||
721 | */ | ||
722 | int | ||
723 | main (int argc, char *const *argv) | ||
724 | { | ||
725 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
726 | GNUNET_GETOPT_OPTION_END | ||
727 | }; | ||
728 | |||
729 | int ret; | ||
730 | |||
731 | GNUNET_log_setup ("fcfsd", "WARNING", NULL); | ||
732 | ret = | ||
733 | (GNUNET_OK == | ||
734 | GNUNET_PROGRAM_run (argc, argv, "fcfsd", | ||
735 | _("GNUnet GNS first come first serve registration service"), | ||
736 | options, | ||
737 | &run, NULL)) ? 0 : 1; | ||
738 | |||
739 | return ret; | ||
740 | } | ||
741 | |||
742 | /* end of gnunet-gns-fcfsd.c */ | ||