aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gnunet-bcd.c
diff options
context:
space:
mode:
authorAlessio Vanni <vannilla@firemail.cc>2021-10-14 21:22:40 +0200
committerAlessio Vanni <vannilla@firemail.cc>2021-11-21 15:23:26 +0100
commit48ccb35c9aea178d7103c3f198946c1bcbcc080c (patch)
treeefa23246d4b5a657d2a311a326346483ff1a5e54 /src/gns/gnunet-bcd.c
parent5cbf93d3c6c7a058d9a7893e2a3583a2b5b30d0e (diff)
downloadgnunet-48ccb35c9aea178d7103c3f198946c1bcbcc080c.tar.gz
gnunet-48ccb35c9aea178d7103c3f198946c1bcbcc080c.zip
Improve gnunet-bcd and update logo used in generated cards
The HTML forms now use a custom CSS instead of importing Bootstrap 4. This new CSS is basd on Bootstrap 5 with some minimal differences to make it look a bit like the older theme. Bootstrap was removed because these pages don't need its full power and also because it was difficult for some text editors to handle the one-long-line minified CSS embedded in the HTML. Since the forms are just a series of label + input elements, using a specific set of directives doesn't add any significant maintenance cost while making editing easiers. A new form to generate a simplified card was added. This card is desgined to reduce the leftover whitespace when some optional entries are left blank in the "full" form, while at the same time giving importance to the QR code containing the GNS address. Its layout can be improved. The simplified form can also be used to generate a PNG picture of the QR code, so that it can be included in other graphical media other than a business card, for example on a flyer or in the signature of a HTML-based e-mail. Generally, the gnunet-bcd service should provide a slightly better user experience, even if it's just to provide different pages for different errors but with a unified style. The logo used in the cards has been changed from the previous "gnu in front of a spiderweb" illustration to the new "gnu-shaped network of peers" image. It is also now a pure TikZ picture instead of being made using PSTricks, because, apparently, there is an incompatibility between the two packages in recent versions which made it impossible to compile the file. As a consequence of the incompatibility between TikZ and PSTricks, the QR code is now generated using the 'qrcode' package. This commit contains some changes to FCFS, but they're just some minor fixes and are unrelated to the changes to BCD.
Diffstat (limited to 'src/gns/gnunet-bcd.c')
-rw-r--r--src/gns/gnunet-bcd.c884
1 files changed, 513 insertions, 371 deletions
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
index a2e94089c..83efcfba5 100644
--- a/src/gns/gnunet-bcd.c
+++ b/src/gns/gnunet-bcd.c
@@ -30,394 +30,522 @@
30#include "gnunet_identity_service.h" 30#include "gnunet_identity_service.h"
31#include "gnunet_mhd_compat.h" 31#include "gnunet_mhd_compat.h"
32 32
33struct StaticResource
34{
35 /**
36 * Handle to file on disk.
37 */
38 struct GNUNET_DISK_FileHandle *handle;
39
40 /**
41 * Size in bytes of the file.
42 */
43 uint64_t size;
44
45 /**
46 * Cached response object to send to clients.
47 */
48 struct MHD_Response *response;
49};
50
51struct ParameterMap
52{
53 /**
54 * Name of the parameter from the request.
55 */
56 char *name;
57
58 /**
59 * Name of the definition in the TeX output.
60 */
61 char *definition;
62};
63
33/** 64/**
34 * Error page to display if submitted GNS key is invalid. 65 * Handle to the HTTP server as provided by libmicrohttpd
35 */ 66 */
36#define INVALID_GNSKEY \ 67static struct MHD_Daemon *httpd = NULL;
37 "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
38 68
39/** 69/**
40 * Error page to display on 404. 70 * Our primary task for the HTTPD.
41 */ 71 */
42#define NOT_FOUND \ 72static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
43 "<html><head><title>Error</title><body>404 not found</body></html>"
44 73
45/** 74/**
46 * Handle to the HTTP server as provided by libmicrohttpd 75 * Index file resource (simple result).
47 */ 76 */
48static struct MHD_Daemon *daemon_handle; 77static struct StaticResource *index_simple = NULL;
49 78
50/** 79/**
51 * Our configuration. 80 * Index file resource (full result).
52 */ 81 */
53static const struct GNUNET_CONFIGURATION_Handle *cfg; 82static struct StaticResource *index_full = NULL;
54 83
55/** 84/**
56 * Our primary task for the HTTPD. 85 * Error: invalid gns key.
57 */ 86 */
58static struct GNUNET_SCHEDULER_Task *http_task; 87static struct StaticResource *key_error = NULL;
59 88
60/** 89/**
61 * Our main website. 90 * Error: 404
62 */ 91 */
63static struct MHD_Response *main_response; 92static struct StaticResource *notfound_error = NULL;
64 93
65/** 94/**
66 * Error: invalid gns key. 95 * Errors after receiving the form data.
67 */ 96 */
68static struct MHD_Response *invalid_gnskey_response; 97static struct StaticResource *internal_error = NULL;
69 98
70/** 99/**
71 * Error: 404 100 * Other errors.
72 */ 101 */
73static struct MHD_Response *not_found_response; 102static struct StaticResource *forbidden_error = NULL;
74 103
75/** 104/**
76 * Absolute name of the 'gns-bcd.tex' file. 105 * Full path to the TeX template file (simple result)
77 */ 106 */
78static char *resfile; 107static char *tex_file_simple = NULL;
79 108
80/** 109/**
81 * Port number. 110 * Full path to the TeX template file (full result)
82 */ 111 */
83static uint16_t port = 8888; 112static char *tex_file_full = NULL;
84 113
114/**
115 * Full path to the TeX template file (PNG result)
116 */
117static char *tex_file_png = NULL;
85 118
86struct Entry 119/**
87{ 120 * Used as a sort of singleton to send exactly one 100 CONTINUE per request.
88 const char *formname; 121 */
89 const char *texname; 122static int continue_100 = 100;
123
124/**
125 * Map of names with TeX definitions, used during PDF generation.
126 */
127static const struct ParameterMap pmap[] = {
128 {"prefix", "prefix"},
129 {"name", "name"},
130 {"suffix", "suffix"},
131 {"street", "street"},
132 {"city", "city"},
133 {"phone", "phone"},
134 {"fax", "fax"},
135 {"email", "email"},
136 {"homepage", "homepage"},
137 {"org", "organization"},
138 {"department", "department"},
139 {"subdepartment", "subdepartment"},
140 {"jobtitle", "jobtitle"},
141 {NULL, NULL},
90}; 142};
91 143
144/**
145 * Port number.
146 */
147static uint16_t port = 8888;
92 148
93/** 149/**
94 * Main request handler. 150 * Task ran at shutdown to clean up everything.
151 *
152 * @param cls unused
95 */ 153 */
96static MHD_RESULT 154static void
97access_handler_callback (void *cls, 155do_shutdown (void *cls)
98 struct MHD_Connection *connection,
99 const char *url,
100 const char *method,
101 const char *version,
102 const char *upload_data,
103 size_t *upload_data_size,
104 void **con_cls)
105{ 156{
106 static int dummy; 157 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
107 static const struct Entry map[] = { { "prefix", "prefix" }, 158 calling `GNUNET_DISK_file_close' would generate a spurious warning message
108 { "name", "name" }, 159 in the log. Since that function does nothing but close the descriptor and
109 { "suffix", "suffix" }, 160 free the allocated memory, After destroying the response all that's left to
110 { "street", "street" }, 161 do is call `GNUNET_free'. */
111 { "city", "city" }, 162 if (NULL != index_simple)
112 { "phone", "phone" },
113 { "fax", "fax" },
114 { "email", "email" },
115 { "homepage", "homepage" },
116 { "orga", "orga" },
117 { "departmenti18n", "departmentde" },
118 { "departmenten", "departmenten" },
119 { "subdepartmenti18n",
120 "subdepartmentde" },
121 { "subdepartmenten", "subdepartmenten" },
122 { "jobtitlei18n", "jobtitlegerman" },
123 { "jobtitleen", "jobtitleenglish" },
124 { "subdepartmenten", "subdepartmenten" },
125 { NULL, NULL } };
126
127 (void) cls;
128 (void) version;
129 (void) upload_data;
130 (void) upload_data_size;
131 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
132 { 163 {
133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 164 MHD_destroy_response (index_simple->response);
134 _ ("Refusing `%s' request to HTTP server\n"), 165 GNUNET_free (index_simple->handle);
135 method); 166 GNUNET_free (index_simple);
136 return MHD_NO;
137 } 167 }
138 if (NULL == *con_cls) 168 if (NULL != index_full)
139 { 169 {
140 (*con_cls) = &dummy; 170 MHD_destroy_response (index_full->response);
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE reply\n"); 171 GNUNET_free (index_full->handle);
142 return MHD_YES; /* send 100 continue */ 172 GNUNET_free (index_full);
143 } 173 }
144 if (0 == strcasecmp (url, "/")) 174 if (NULL != key_error)
145 return MHD_queue_response (connection, MHD_HTTP_OK, main_response);
146 if (0 == strcasecmp (url, "/submit.pdf"))
147 { 175 {
148 unsigned int i; 176 MHD_destroy_response (key_error->response);
149 char *p; 177 GNUNET_free (key_error->handle);
150 char *tmp; 178 GNUNET_free (key_error);
151 char *deffile; 179 }
152 struct GNUNET_IDENTITY_PublicKey pub; 180 if (NULL != notfound_error)
153 size_t slen; 181 {
154 FILE *f; 182 MHD_destroy_response (notfound_error->response);
155 struct stat st; 183 GNUNET_free (notfound_error->handle);
156 struct MHD_Response *response; 184 GNUNET_free (notfound_error);
157 int fd; 185 }
158 MHD_RESULT ret; 186 if (NULL != internal_error)
159 187 {
160 const char *gpg_fp = MHD_lookup_connection_value (connection, 188 MHD_destroy_response (internal_error->response);
161 MHD_GET_ARGUMENT_KIND, 189 GNUNET_free (internal_error->handle);
162 "gpgfingerprint"); 190 GNUNET_free (internal_error);
163 const char *gns_nick = MHD_lookup_connection_value (connection, 191 }
164 MHD_GET_ARGUMENT_KIND, 192 if (NULL != forbidden_error)
165 "gnsnick"); 193 {
166 const char *gnskey = 194 MHD_destroy_response (forbidden_error->response);
167 MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "gnskey"); 195 GNUNET_free (forbidden_error->handle);
168 if ((NULL == gnskey) || 196 GNUNET_free (forbidden_error);
169 (GNUNET_OK !=
170 GNUNET_IDENTITY_public_key_from_string (gnskey,
171 &pub)))
172 {
173 return MHD_queue_response (connection,
174 MHD_HTTP_OK,
175 invalid_gnskey_response);
176 }
177 tmp = GNUNET_DISK_mkdtemp (gnskey);
178 if (NULL == tmp)
179 {
180 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
181 return MHD_NO;
182 }
183 GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "def.tex");
184 f = fopen (deffile, "w");
185 if (NULL == f)
186 {
187 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
188 GNUNET_free (deffile);
189 GNUNET_DISK_directory_remove (tmp);
190 GNUNET_free (tmp);
191 return MHD_NO;
192 }
193 for (i = 0; NULL != map[i].formname; i++)
194 {
195 const char *val = MHD_lookup_connection_value (connection,
196 MHD_GET_ARGUMENT_KIND,
197 map[i].formname);
198 if (NULL != val)
199 fprintf (f, "\\def\\%s{%s}\n", map[i].texname, val);
200 else
201 fprintf (f, "\\def\\%s{}\n", map[i].texname);
202 }
203 if (NULL != gpg_fp)
204 {
205 char *gpg1;
206 char *gpg2;
207
208 slen = strlen (gpg_fp);
209 gpg1 = GNUNET_strndup (gpg_fp, slen / 2);
210 gpg2 = GNUNET_strdup (&gpg_fp[slen / 2]);
211 fprintf (f, "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n", gpg1, gpg2);
212 GNUNET_free (gpg2);
213 GNUNET_free (gpg1);
214 }
215 fprintf (f,
216 "\\def\\gns{%s/%s}\n",
217 gnskey,
218 (NULL == gns_nick) ? "" : gns_nick);
219 fclose (f);
220 GNUNET_asprintf (
221 &p,
222 "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
223 tmp,
224 resfile);
225 GNUNET_free (deffile);
226 ret = system (p);
227 if (WIFSIGNALED (ret) || (0 != WEXITSTATUS (ret)))
228 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", p);
229 GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
230 fd = open (deffile, O_RDONLY);
231 if (-1 == fd)
232 {
233 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
234 GNUNET_free (deffile);
235 GNUNET_free (p);
236 GNUNET_DISK_directory_remove (tmp);
237 GNUNET_free (tmp);
238 return MHD_NO;
239 }
240 GNUNET_break (0 == stat (deffile, &st));
241 if (NULL ==
242 (response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
243 {
244 GNUNET_break (0);
245 GNUNET_break (0 == close (fd));
246 GNUNET_free (deffile);
247 GNUNET_free (p);
248 GNUNET_DISK_directory_remove (tmp);
249 GNUNET_free (tmp);
250 return MHD_NO;
251 }
252 (void) MHD_add_response_header (response,
253 MHD_HTTP_HEADER_CONTENT_TYPE,
254 "application/pdf");
255 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
256 MHD_destroy_response (response);
257 GNUNET_free (deffile);
258 GNUNET_free (p);
259 GNUNET_DISK_directory_remove (tmp);
260 GNUNET_free (tmp);
261 return ret;
262 } 197 }
263 return MHD_queue_response (connection,
264 MHD_HTTP_NOT_FOUND,
265 not_found_response);
266}
267
268
269/**
270 * Function that queries MHD's select sets and
271 * starts the task waiting for them.
272 */
273static struct GNUNET_SCHEDULER_Task *
274prepare_daemon (struct MHD_Daemon *daemon_handle);
275 198
199 if (NULL != httpd_task)
200 {
201 GNUNET_SCHEDULER_cancel (httpd_task);
202 }
203 if (NULL != httpd)
204 {
205 MHD_stop_daemon (httpd);
206 }
207}
276 208
277/** 209/**
278 * Call MHD to process pending requests and then go back 210 * Called when the HTTP server has some pending operations.
279 * and schedule the next run. 211 *
212 * @param cls unused
280 */ 213 */
281static void 214static void
282run_daemon (void *cls) 215do_httpd (void *cls);
283{
284 struct MHD_Daemon *daemon_handle = cls;
285
286 http_task = NULL;
287 GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
288 http_task = prepare_daemon (daemon_handle);
289}
290
291 216
292/** 217/**
293 * Function that queries MHD's select sets and 218 * Schedule a task to run MHD.
294 * starts the task waiting for them.
295 */ 219 */
296static struct GNUNET_SCHEDULER_Task * 220static void
297prepare_daemon (struct MHD_Daemon *daemon_handle) 221run_httpd (void)
298{ 222{
299 struct GNUNET_SCHEDULER_Task *ret;
300 fd_set rs; 223 fd_set rs;
301 fd_set ws; 224 fd_set ws;
302 fd_set es; 225 fd_set es;
303 struct GNUNET_NETWORK_FDSet *wrs; 226
304 struct GNUNET_NETWORK_FDSet *wws; 227 struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create ();
305 int max; 228 struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create ();
306 MHD_UNSIGNED_LONG_LONG timeout; 229 struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create ();
307 int haveto;
308 struct GNUNET_TIME_Relative tv;
309 230
310 FD_ZERO (&rs); 231 FD_ZERO (&rs);
311 FD_ZERO (&ws); 232 FD_ZERO (&ws);
312 FD_ZERO (&es); 233 FD_ZERO (&es);
313 wrs = GNUNET_NETWORK_fdset_create (); 234
314 wws = GNUNET_NETWORK_fdset_create (); 235 int max = -1;
315 max = -1; 236 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
316 GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); 237
317 haveto = MHD_get_timeout (daemon_handle, &timeout); 238 unsigned MHD_LONG_LONG timeout = 0;
318 if (haveto == MHD_YES) 239 struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL;
319 tv.rel_value_us = (uint64_t) timeout * 1000LL; 240 if (MHD_YES == MHD_get_timeout (httpd, &timeout))
320 else 241 {
321 tv = GNUNET_TIME_UNIT_FOREVER_REL; 242 gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
322 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); 243 timeout);
323 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); 244 }
324 ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, 245
325 tv, 246 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
326 wrs, 247 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
327 wws, 248 GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
328 &run_daemon, 249
329 daemon_handle); 250 httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
330 GNUNET_NETWORK_fdset_destroy (wrs); 251 gtime,
331 GNUNET_NETWORK_fdset_destroy (wws); 252 grs,
332 return ret; 253 gws,
254 &do_httpd,
255 NULL);
256 GNUNET_NETWORK_fdset_destroy (grs);
257 GNUNET_NETWORK_fdset_destroy (gws);
258 GNUNET_NETWORK_fdset_destroy (ges);
333} 259}
334 260
261/**
262 * Called when the HTTP server has some pending operations.
263 *
264 * @param cls unused
265 */
266static void
267do_httpd (void *cls)
268{
269 httpd_task = NULL;
270 MHD_run (httpd);
271 run_httpd ();
272}
335 273
336/** 274/**
337 * Start server offering our hostlist. 275 * Send a response back to a connected client.
338 * 276 *
339 * @return #GNUNET_OK on success 277 * @param cls unused
278 * @param connection the connection with the client
279 * @param url the requested address
280 * @param method the HTTP method used
281 * @param version the protocol version (including the "HTTP/" part)
282 * @param upload_data data sent with a POST request
283 * @param upload_data_size length in bytes of the POST data
284 * @param ptr used to pass data between request handling phases
285 * @return MHD_NO on error
340 */ 286 */
341static int 287static MHD_RESULT
342server_start () 288create_response (void *cls,
289 struct MHD_Connection *connection,
290 const char *url,
291 const char *method,
292 const char *version,
293 const char *upload_data,
294 size_t *upload_data_size,
295 void **ptr)
343{ 296{
344 if (0 == port) 297 (void) cls;
298 (void) version;
299 (void) upload_data;
300 (void) upload_data_size;
301
302 bool isget = (0 == strcmp (method, MHD_HTTP_METHOD_GET));
303 bool ishead = (0 == strcmp (method, MHD_HTTP_METHOD_HEAD));
304
305 if (!isget && !ishead)
345 { 306 {
346 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 307 return MHD_queue_response (connection,
347 _ ("Invalid port number %u. Exiting.\n"), 308 MHD_HTTP_NOT_IMPLEMENTED,
348 port); 309 forbidden_error->response);
349 return GNUNET_SYSERR;
350 } 310 }
351 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 311
352 _ ("Businesscard HTTP server starts on %u\n"), 312 if (ishead)
353 port);
354 daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
355 port,
356 NULL /* accept_policy_callback */,
357 NULL,
358 &access_handler_callback,
359 NULL,
360 MHD_OPTION_CONNECTION_LIMIT,
361 (unsigned int) 512,
362 MHD_OPTION_PER_IP_CONNECTION_LIMIT,
363 (unsigned int) 2,
364 MHD_OPTION_CONNECTION_TIMEOUT,
365 (unsigned int) 60,
366 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
367 (size_t) (16 * 1024),
368 MHD_OPTION_END);
369 if (NULL == daemon_handle)
370 { 313 {
371 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 314 /* Dedicated branch in case we want to provide a different result for some
372 _ ("Could not start businesscard HTTP server on port %u\n"), 315 reason (e.g. a non-web browser application using the web UI) */
373 (unsigned int) port); 316 return MHD_queue_response (connection,
374 return GNUNET_SYSERR; 317 MHD_HTTP_OK,
318 index_simple->response);
375 } 319 }
376 http_task = prepare_daemon (daemon_handle);
377 return GNUNET_OK;
378}
379 320
321 /* Send a 100 CONTINUE response to tell clients that the result of the
322 request might take some time */
323 if (NULL == *ptr)
324 {
325 *ptr = &continue_100;
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE\n");
327 return MHD_YES;
328 }
380 329
381/** 330 if (0 == strcmp ("/", url))
382 * Stop HTTP server. 331 {
383 */ 332 return MHD_queue_response (connection,
384static void 333 MHD_HTTP_OK,
385server_stop (void *cls) 334 index_simple->response);
386{ 335 }
387 (void) cls; 336
388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "HTTP server shutdown\n"); 337 if (0 == strcmp ("/full", url))
389 if (NULL != http_task) 338 {
339 return MHD_queue_response (connection,
340 MHD_HTTP_OK,
341 index_full->response);
342 }
343
344 bool isfull = (0 == strcmp ("/submit/full", url));
345 bool issimple = (0 == strcmp ("/submit/simple", url));
346
347 if (!isfull && !issimple)
348 {
349 return MHD_queue_response (connection,
350 MHD_HTTP_NOT_FOUND,
351 notfound_error->response);
352 }
353
354 const char *gpgfp = MHD_lookup_connection_value (connection,
355 MHD_GET_ARGUMENT_KIND,
356 "gpgfingerprint");
357 const char *gnsnick = MHD_lookup_connection_value (connection,
358 MHD_GET_ARGUMENT_KIND,
359 "gnsnick");
360 const char *gnskey = MHD_lookup_connection_value (connection,
361 MHD_GET_ARGUMENT_KIND,
362 "gnskey");
363 const char *qrpng = MHD_lookup_connection_value (connection,
364 MHD_GET_ARGUMENT_KIND,
365 "gnspng");
366
367 struct GNUNET_IDENTITY_PublicKey pk;
368 if (NULL == gnskey
369 || GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (gnskey, &pk))
370 {
371 return MHD_queue_response (connection,
372 MHD_HTTP_BAD_REQUEST,
373 key_error->response);
374 }
375
376 char *tmpd = GNUNET_DISK_mkdtemp (gnskey);
377 if (NULL == tmpd)
378 {
379 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
380 return MHD_queue_response (connection,
381 MHD_HTTP_INTERNAL_SERVER_ERROR,
382 internal_error->response);
383 }
384
385 char *defpath = NULL;
386 GNUNET_asprintf (&defpath, "%s%s%s", tmpd, DIR_SEPARATOR_STR, "def.tex");
387
388 FILE *deffile = fopen (defpath, "w");
389 if (NULL == deffile)
390 { 390 {
391 GNUNET_SCHEDULER_cancel (http_task); 391 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath);
392 http_task = NULL; 392 GNUNET_free (defpath);
393 GNUNET_DISK_directory_remove (tmpd);
394 GNUNET_free (tmpd);
395 return MHD_queue_response (connection,
396 MHD_HTTP_INTERNAL_SERVER_ERROR,
397 internal_error->response);
393 } 398 }
394 if (NULL != daemon_handle) 399
400 GNUNET_free (defpath);
401
402 for (size_t i=0; NULL!=pmap[i].name; ++i)
395 { 403 {
396 MHD_stop_daemon (daemon_handle); 404 const char *value = MHD_lookup_connection_value (connection,
397 daemon_handle = NULL; 405 MHD_GET_ARGUMENT_KIND,
406 pmap[i].name);
407 fprintf (deffile,
408 "\\def\\%s{%s}\n",
409 pmap[i].definition,
410 (NULL == value) ? "" : value);
398 } 411 }
399 if (NULL != main_response) 412
413 if (NULL != gpgfp)
400 { 414 {
401 MHD_destroy_response (main_response); 415 size_t len = strlen (gpgfp);
402 main_response = NULL; 416 char *line1 = GNUNET_strndup (gpgfp, len/2);
417 char *line2 = GNUNET_strdup (&gpgfp[len/2]);
418 fprintf (deffile,
419 "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
420 line1,
421 line2);
403 } 422 }
404 if (NULL != invalid_gnskey_response) 423
424 fprintf (deffile,
425 "\\def\\gns{%s/%s}\n",
426 gnskey,
427 (NULL == gnsnick) ? "" : gnsnick);
428
429 fclose (deffile);
430
431 char *command = NULL;
432 GNUNET_asprintf (&command,
433 "cd %s; cp %s gns-bcd.tex; "
434 "pdflatex %s gns-bcd.tex >/dev/null 2>&1",
435 tmpd,
436 (isfull) ? tex_file_full :
437 ((NULL == qrpng) ? tex_file_simple : tex_file_png),
438 (NULL == qrpng) ? "" : "-shell-escape");
439
440 int ret = system (command);
441
442 GNUNET_free (command);
443
444 if (WIFSIGNALED (ret) || 0 != WEXITSTATUS (ret))
405 { 445 {
406 MHD_destroy_response (invalid_gnskey_response); 446 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", command);
407 invalid_gnskey_response = NULL;
408 } 447 }
409 if (NULL != not_found_response) 448
449 GNUNET_asprintf (&defpath,
450 "%s%s%s",
451 tmpd,
452 DIR_SEPARATOR_STR,
453 (NULL == qrpng) ? "gns-bcd.pdf" : "gns-bcd.png");
454
455 int pdf = open (defpath, O_RDONLY);
456 if (-1 == pdf)
410 { 457 {
411 MHD_destroy_response (not_found_response); 458 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath);
412 not_found_response = NULL; 459 GNUNET_free (defpath);
460 GNUNET_DISK_directory_remove (tmpd);
461 GNUNET_free (tmpd);
462 return MHD_queue_response (connection,
463 MHD_HTTP_INTERNAL_SERVER_ERROR,
464 internal_error->response);
413 } 465 }
414 if (NULL != resfile) 466
467 struct stat statret;
468 GNUNET_break (0 == stat (defpath, &statret));
469
470 GNUNET_free (defpath);
471
472 struct MHD_Response *pdfrs =
473 MHD_create_response_from_fd ((size_t) statret.st_size, pdf);
474 if (NULL == pdfrs)
415 { 475 {
416 GNUNET_free (resfile); 476 GNUNET_break (0);
417 resfile = NULL; 477 GNUNET_break (0 == close (pdf));
478 GNUNET_DISK_directory_remove (tmpd);
479 GNUNET_free (tmpd);
480 return MHD_queue_response (connection,
481 MHD_HTTP_INTERNAL_SERVER_ERROR,
482 internal_error->response);
418 } 483 }
484
485 MHD_add_response_header (pdfrs,
486 MHD_HTTP_HEADER_CONTENT_TYPE,
487 (NULL == qrpng) ? "application/pdf" : "image/png");
488 MHD_add_response_header (pdfrs,
489 MHD_HTTP_HEADER_CONTENT_DISPOSITION,
490 (NULL == qrpng) ?
491 "attachment; filename=\"gns-business-card.pdf\"" :
492 "attachment; filename=\"gns-qr-code.png\"");
493 MHD_RESULT r = MHD_queue_response (connection, MHD_HTTP_OK, pdfrs);
494
495 MHD_destroy_response (pdfrs);
496 GNUNET_DISK_directory_remove (tmpd);
497 GNUNET_free (tmpd);
498
499 return r;
419} 500}
420 501
502/**
503 * Open a file on disk and generate a response for it.
504 *
505 * @param name name of the file to open
506 * @param basedir directory where the file is located
507 * @return NULL on error
508 */
509static struct StaticResource *
510open_static_resource (const char *name, const char *basedir)
511{
512 char *fullname = NULL;
513 GNUNET_asprintf (&fullname, "%s%s%s", basedir, DIR_SEPARATOR_STR, name);
514
515 struct GNUNET_DISK_FileHandle *f =
516 GNUNET_DISK_file_open (fullname,
517 GNUNET_DISK_OPEN_READ,
518 GNUNET_DISK_PERM_NONE);
519
520 GNUNET_free (fullname);
521
522 if (NULL == f)
523 {
524 return NULL;
525 }
526
527 off_t size = 0;
528 if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size))
529 {
530 GNUNET_DISK_file_close (f);
531 return NULL;
532 }
533
534 struct MHD_Response *response = MHD_create_response_from_fd64 (size, f->fd);
535
536 if (NULL == response)
537 {
538 GNUNET_DISK_file_close (f);
539 return NULL;
540 }
541
542 struct StaticResource *res = GNUNET_new (struct StaticResource);
543 res->handle = f;
544 res->size = (uint64_t) size;
545 res->response = response;
546
547 return res;
548}
421 549
422/** 550/**
423 * Main function that will be run. 551 * Main function that will be run.
@@ -433,63 +561,84 @@ run (void *cls,
433 const char *cfgfile, 561 const char *cfgfile,
434 const struct GNUNET_CONFIGURATION_Handle *c) 562 const struct GNUNET_CONFIGURATION_Handle *c)
435{ 563{
436 struct stat st;
437 char *dir;
438 char *fn;
439 int fd;
440
441 (void) cls; 564 (void) cls;
442 (void) args; 565 (void) args;
443 (void) cfgfile; 566 (void) cfgfile;
444 cfg = c; 567
445 dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); 568 if (0 == port)
446 GNUNET_assert (NULL != dir);
447 GNUNET_asprintf (&fn, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.html");
448 GNUNET_asprintf (&resfile, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.tex");
449 GNUNET_free (dir);
450 fd = open (fn, O_RDONLY);
451 if (-1 == fd)
452 { 569 {
453 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); 570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
454 GNUNET_free (fn); 571 _ ("Invalid port number %u\n"),
572 port);
573 GNUNET_SCHEDULER_shutdown ();
455 return; 574 return;
456 } 575 }
457 if (0 != stat (fn, &st)) 576
577 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
578
579 char *datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
580 GNUNET_assert (NULL != datadir);
581
582 GNUNET_asprintf (&tex_file_full,
583 "%s%s%s",
584 datadir,
585 DIR_SEPARATOR_STR,
586 "gns-bcd.tex");
587 GNUNET_asprintf (&tex_file_simple,
588 "%s%s%s",
589 datadir,
590 DIR_SEPARATOR_STR,
591 "gns-bcd-simple.tex");
592 GNUNET_asprintf(&tex_file_png,
593 "%s%s%s",
594 datadir,
595 DIR_SEPARATOR_STR,
596 "gns-bcd-png.tex");
597
598 index_simple = open_static_resource ("gns-bcd-simple.html", datadir);
599 index_full = open_static_resource ("gns-bcd.html", datadir);
600 key_error = open_static_resource ("gns-bcd-invalid-key.html", datadir);
601 notfound_error = open_static_resource ("gns-bcd-not-found.html", datadir);
602 internal_error = open_static_resource ("gns-bcd-internal-error.html", datadir);
603 forbidden_error = open_static_resource ("gns-bcd-forbidden.html", datadir);
604
605 GNUNET_free (datadir);
606
607 if ((NULL == index_simple) || (NULL == index_full)
608 || (NULL == key_error) || (NULL == notfound_error)
609 || (NULL == internal_error) || (NULL == forbidden_error))
458 { 610 {
459 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); 611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
460 GNUNET_free (fn); 612 _ ("Unable to set up the daemon\n"));
461 GNUNET_break (0 == close (fd)); 613 GNUNET_SCHEDULER_shutdown ();
462 return; 614 return;
463 } 615 }
464 GNUNET_free (fn); 616
465 if (NULL == 617 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
466 (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd))) 618 do
467 { 619 {
468 GNUNET_break (0); 620 httpd = MHD_start_daemon (flags,
469 GNUNET_break (0 == close (fd)); 621 port,
622 NULL, NULL,
623 &create_response, NULL,
624 MHD_OPTION_CONNECTION_LIMIT, 512,
625 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
626 MHD_OPTION_CONNECTION_TIMEOUT, 60,
627 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 16 * 1024,
628 MHD_OPTION_END);
629 flags = MHD_USE_DEBUG;
630 } while (NULL == httpd && flags != MHD_USE_DEBUG);
631
632 if (NULL == httpd)
633 {
634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
635 _ ("Failed to start HTTP server\n"));
636 GNUNET_SCHEDULER_shutdown ();
470 return; 637 return;
471 } 638 }
472 (void) MHD_add_response_header (main_response,
473 MHD_HTTP_HEADER_CONTENT_TYPE,
474 "text/html");
475 invalid_gnskey_response =
476 MHD_create_response_from_buffer (strlen (INVALID_GNSKEY),
477 INVALID_GNSKEY,
478 MHD_RESPMEM_PERSISTENT);
479 (void) MHD_add_response_header (invalid_gnskey_response,
480 MHD_HTTP_HEADER_CONTENT_TYPE,
481 "text/html");
482 not_found_response = MHD_create_response_from_buffer (strlen (NOT_FOUND),
483 NOT_FOUND,
484 MHD_RESPMEM_PERSISTENT);
485 (void) MHD_add_response_header (not_found_response,
486 MHD_HTTP_HEADER_CONTENT_TYPE,
487 "text/html");
488 if (GNUNET_OK != server_start ())
489 return;
490 GNUNET_SCHEDULER_add_shutdown (&server_stop, NULL);
491}
492 639
640 run_httpd ();
641}
493 642
494/** 643/**
495 * The main function for gnunet-gns. 644 * The main function for gnunet-gns.
@@ -502,32 +651,25 @@ int
502main (int argc, char *const *argv) 651main (int argc, char *const *argv)
503{ 652{
504 struct GNUNET_GETOPT_CommandLineOption options[] = { 653 struct GNUNET_GETOPT_CommandLineOption options[] = {
505 GNUNET_GETOPT_option_uint16 ('p', 654 GNUNET_GETOPT_option_uint16 (
506 "port", 655 'p',
507 "PORT", 656 "port",
508 gettext_noop ( 657 "PORT",
509 "Run HTTP serve on port PORT (default is 8888)"), 658 gettext_noop ("Run HTTP server on port PORT (default is 8888)"),
510 &port), 659 &port),
511 GNUNET_GETOPT_OPTION_END 660 GNUNET_GETOPT_OPTION_END,
512 }; 661 };
513 int ret;
514
515 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
516 return 2;
517 GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL);
518 ret = (GNUNET_OK ==
519 GNUNET_PROGRAM_run (argc,
520 argv,
521 "gnunet-bcd",
522 _ ("GNUnet HTTP server to create business cards"),
523 options,
524 &run,
525 NULL))
526 ? 0
527 : 1;
528 GNUNET_free_nz ((void *) argv);
529 return ret;
530}
531 662
663 return ((GNUNET_OK ==
664 GNUNET_PROGRAM_run (argc,
665 argv,
666 "gnunet-bcd",
667 _ ("GNUnet HTTP server to create business cards"),
668 options,
669 &run,
670 NULL))
671 ? 0
672 : 1);
673}
532 674
533/* end of gnunet-bcd.c */ 675/* end of gnunet-bcd.c */