Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020, 2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file util/secmod_common.c
18 : * @brief Common functions for the exchange security modules
19 : * @author Florian Dold <dold@taler.net>
20 : */
21 : #include "platform.h"
22 : #include "taler/taler_util.h"
23 : #include "secmod_common.h"
24 : #include <poll.h>
25 : #ifdef __linux__
26 : #include <sys/eventfd.h>
27 : #endif
28 :
29 :
30 : char *
31 263 : TES_normalize_section (const char *section)
32 : {
33 263 : char *result = GNUNET_strdup (section);
34 :
35 4864 : for (char *p = result; '\0' != *p; p++)
36 4601 : *p = (char) tolower ((unsigned char) *p);
37 263 : return result;
38 : }
39 :
40 :
41 : /**
42 : * A denomination directory to rename after checking for conflicts.
43 : */
44 : struct KeyDirectory
45 : {
46 : char *old_name;
47 : char *new_name;
48 : };
49 :
50 :
51 : /**
52 : * Closure for #check_section_name and #collect_key_directory.
53 : */
54 : struct KeyDirectoryContext
55 : {
56 : const char *cprefix;
57 : struct KeyDirectory *dirs;
58 : unsigned int num_dirs;
59 : bool invalid_section_name;
60 : };
61 :
62 :
63 : /**
64 : * Reject section names that would use nested key directories.
65 : *
66 : * @param cls a `struct KeyDirectoryContext`
67 : * @param section configuration section name to check
68 : */
69 : static void
70 1936 : check_section_name (void *cls,
71 : const char *section)
72 : {
73 1936 : struct KeyDirectoryContext *ctx = cls;
74 1936 : size_t prefix_len = strlen (ctx->cprefix);
75 :
76 1936 : if ( (0 != strncasecmp (section,
77 : ctx->cprefix,
78 268 : prefix_len)) ||
79 268 : (NULL == strchr (section + prefix_len, '/')) )
80 1928 : return;
81 8 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
82 : "Invalid denomination section `%s': suffix must not contain '/'\n",
83 : section);
84 8 : ctx->invalid_section_name = true;
85 : }
86 :
87 :
88 : /**
89 : * Collect directories requiring migration without modifying the directory
90 : * being scanned. Reject symlinks and check all destinations before starting
91 : * the migration.
92 : *
93 : * @param cls a `struct KeyDirectoryContext`
94 : * @param filename directory entry to inspect
95 : * @return #GNUNET_OK to continue, #GNUNET_SYSERR on a symlink, conflict or I/O error
96 : */
97 : static enum GNUNET_GenericReturnValue
98 153 : collect_key_directory (void *cls,
99 : const char *filename)
100 : {
101 153 : struct KeyDirectoryContext *ctx = cls;
102 153 : const char *base = strrchr (filename, '/') + 1;
103 : struct KeyDirectory dir;
104 : struct stat sb;
105 : struct stat target;
106 : char *normalized;
107 :
108 153 : if (0 != lstat (filename, &sb))
109 : {
110 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
111 : "lstat",
112 : filename);
113 0 : return GNUNET_SYSERR;
114 : }
115 153 : if (S_ISLNK (sb.st_mode))
116 : {
117 12 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
118 : "Invalid key directory entry `%s': symbolic links are not allowed\n",
119 : filename);
120 12 : return GNUNET_SYSERR;
121 : }
122 141 : if (0 != strncasecmp (base,
123 : ctx->cprefix,
124 : strlen (ctx->cprefix)))
125 4 : return GNUNET_OK;
126 137 : if (! S_ISDIR (sb.st_mode))
127 0 : return GNUNET_OK;
128 137 : normalized = TES_normalize_section (base);
129 137 : if (0 == strcmp (base, normalized))
130 : {
131 109 : GNUNET_free (normalized);
132 109 : return GNUNET_OK;
133 : }
134 28 : GNUNET_asprintf (&dir.new_name,
135 : "%.*s%s",
136 28 : (int) (base - filename),
137 : filename,
138 : normalized);
139 28 : GNUNET_free (normalized);
140 36 : for (unsigned int i = 0; i < ctx->num_dirs; i++)
141 : {
142 10 : if (0 != strcmp (dir.new_name, ctx->dirs[i].new_name))
143 8 : continue;
144 2 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
145 : "Conflicting denomination key directories `%s' and `%s'; resolve their capitalization before restarting\n",
146 : filename,
147 : ctx->dirs[i].old_name);
148 2 : GNUNET_free (dir.new_name);
149 2 : return GNUNET_SYSERR;
150 : }
151 26 : if (0 == lstat (dir.new_name, &target))
152 : {
153 : /* On a case-insensitive filesystem both spellings may already refer to
154 : the same directory. Still rename it to update the stored spelling. */
155 4 : if ( (sb.st_dev != target.st_dev) ||
156 4 : (sb.st_ino != target.st_ino) )
157 : {
158 4 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
159 : "Cannot rename denomination key directory `%s' to `%s': destination exists; resolve the conflict before restarting\n",
160 : filename,
161 : dir.new_name);
162 4 : GNUNET_free (dir.new_name);
163 4 : return GNUNET_SYSERR;
164 : }
165 : }
166 22 : else if (ENOENT != errno)
167 : {
168 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
169 : "lstat",
170 : dir.new_name);
171 0 : GNUNET_free (dir.new_name);
172 0 : return GNUNET_SYSERR;
173 : }
174 22 : dir.old_name = GNUNET_strdup (filename);
175 22 : GNUNET_array_append (ctx->dirs, ctx->num_dirs, dir);
176 22 : return GNUNET_OK;
177 : }
178 :
179 :
180 : enum GNUNET_GenericReturnValue
181 70 : TES_normalize_key_directory (const struct GNUNET_CONFIGURATION_Handle *cfg,
182 : const char *keydir,
183 : const char *cprefix)
184 : {
185 70 : struct KeyDirectoryContext ctx = {
186 : .cprefix = cprefix
187 : };
188 70 : enum GNUNET_GenericReturnValue ret = GNUNET_OK;
189 :
190 70 : GNUNET_CONFIGURATION_iterate_sections (cfg,
191 : &check_section_name,
192 : &ctx);
193 70 : if (ctx.invalid_section_name)
194 8 : return GNUNET_SYSERR;
195 62 : if (GNUNET_OK != GNUNET_DISK_directory_create (keydir))
196 0 : return GNUNET_SYSERR;
197 62 : if (0 > GNUNET_DISK_directory_scan (keydir,
198 : &collect_key_directory,
199 : &ctx))
200 18 : ret = GNUNET_SYSERR;
201 84 : for (unsigned int i = 0; i < ctx.num_dirs; i++)
202 : {
203 22 : struct KeyDirectory *dir = &ctx.dirs[i];
204 :
205 22 : if (GNUNET_OK == ret)
206 : {
207 6 : if (0 != rename (dir->old_name, dir->new_name))
208 : {
209 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
210 : "rename",
211 : dir->old_name);
212 0 : ret = GNUNET_SYSERR;
213 : }
214 : else
215 : {
216 6 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
217 : "Renamed denomination key directory `%s' to `%s'\n",
218 : dir->old_name,
219 : dir->new_name);
220 : }
221 : }
222 22 : GNUNET_free (dir->old_name);
223 22 : GNUNET_free (dir->new_name);
224 : }
225 62 : GNUNET_free (ctx.dirs);
226 62 : return ret;
227 : }
228 :
229 :
230 : /**
231 : * Head of DLL of clients connected to us.
232 : */
233 : struct TES_Client *TES_clients_head;
234 :
235 : /**
236 : * Tail of DLL of clients connected to us.
237 : */
238 : struct TES_Client *TES_clients_tail;
239 :
240 : /**
241 : * Lock for the client queue.
242 : */
243 : pthread_mutex_t TES_clients_lock = PTHREAD_MUTEX_INITIALIZER;
244 :
245 : /**
246 : * Private key of this security module. Used to sign denomination key
247 : * announcements.
248 : */
249 : struct TALER_SecurityModulePrivateKeyP TES_smpriv;
250 :
251 : /**
252 : * Public key of this security module.
253 : */
254 : struct TALER_SecurityModulePublicKeyP TES_smpub;
255 :
256 : /**
257 : * Our listen socket.
258 : */
259 : static struct GNUNET_NETWORK_Handle *unix_sock;
260 :
261 : /**
262 : * Path where we are listening.
263 : */
264 : static char *unixpath;
265 :
266 : /**
267 : * Task run to accept new inbound connections.
268 : */
269 : static struct GNUNET_SCHEDULER_Task *listen_task;
270 :
271 : /**
272 : * Set once we are in shutdown and workers should terminate.
273 : */
274 : static volatile bool in_shutdown;
275 :
276 :
277 : enum GNUNET_GenericReturnValue
278 4949 : TES_transmit_raw (int sock,
279 : size_t end,
280 : const void *pos)
281 : {
282 4949 : size_t off = 0;
283 :
284 4949 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
285 : "Sending message of length %u\n",
286 : (unsigned int) end);
287 9875 : while (off < end)
288 : {
289 4933 : ssize_t ret = send (sock,
290 : pos,
291 : end - off,
292 : 0 /* no flags => blocking! */);
293 :
294 4926 : if ( (-1 == ret) &&
295 0 : ( (EAGAIN == errno) ||
296 0 : (EINTR == errno) ) )
297 : {
298 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG,
299 : "send");
300 0 : continue;
301 : }
302 4926 : if (-1 == ret)
303 : {
304 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
305 : "send");
306 0 : return GNUNET_SYSERR;
307 : }
308 4926 : if (0 == ret)
309 : {
310 0 : GNUNET_break (0);
311 0 : return GNUNET_SYSERR;
312 : }
313 4926 : off += ret;
314 4926 : pos += ret;
315 : }
316 4942 : return GNUNET_OK;
317 : }
318 :
319 :
320 : enum GNUNET_GenericReturnValue
321 4877 : TES_transmit (int sock,
322 : const struct GNUNET_MessageHeader *hdr)
323 : {
324 4877 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
325 : "Sending message of type %u and length %u\n",
326 : (unsigned int) ntohs (hdr->type),
327 : (unsigned int) ntohs (hdr->size));
328 9755 : return TES_transmit_raw (sock,
329 4879 : ntohs (hdr->size),
330 : hdr);
331 : }
332 :
333 :
334 : struct GNUNET_NETWORK_Handle *
335 62 : TES_open_socket (const char *my_unixpath)
336 : {
337 : int sock;
338 : mode_t old_umask;
339 62 : struct GNUNET_NETWORK_Handle *ret = NULL;
340 :
341 : /* Change permissions so that group read/writes are allowed.
342 : * We need this for multi-user exchange deployment with privilege
343 : * separation, where taler-exchange-httpd is part of a group
344 : * that allows it to talk to secmod.
345 : */
346 62 : old_umask = umask (S_IROTH | S_IWOTH | S_IXOTH);
347 :
348 62 : sock = socket (PF_UNIX,
349 : SOCK_STREAM,
350 : 0);
351 62 : if (-1 == sock)
352 : {
353 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
354 : "socket");
355 0 : goto cleanup;
356 : }
357 : {
358 : struct sockaddr_un un;
359 :
360 62 : if (GNUNET_OK !=
361 62 : GNUNET_DISK_directory_create_for_file (my_unixpath))
362 : {
363 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
364 : "mkdir(dirname)",
365 : my_unixpath);
366 : }
367 62 : if (0 != unlink (my_unixpath))
368 : {
369 62 : if (ENOENT != errno)
370 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
371 : "unlink",
372 : my_unixpath);
373 : }
374 62 : memset (&un,
375 : 0,
376 : sizeof (un));
377 62 : un.sun_family = AF_UNIX;
378 62 : strncpy (un.sun_path,
379 : my_unixpath,
380 : sizeof (un.sun_path) - 1);
381 62 : if (0 != bind (sock,
382 : (const struct sockaddr *) &un,
383 : sizeof (un)))
384 : {
385 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
386 : "bind",
387 : my_unixpath);
388 0 : GNUNET_break (0 == close (sock));
389 0 : goto cleanup;
390 : }
391 62 : ret = GNUNET_NETWORK_socket_box_native (sock);
392 62 : if (GNUNET_OK !=
393 62 : GNUNET_NETWORK_socket_listen (ret,
394 : 512))
395 : {
396 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
397 : "listen",
398 : my_unixpath);
399 0 : GNUNET_break (GNUNET_OK ==
400 : GNUNET_NETWORK_socket_close (ret));
401 0 : ret = NULL;
402 : }
403 : }
404 62 : cleanup:
405 62 : (void) umask (old_umask);
406 62 : return ret;
407 : }
408 :
409 :
410 : void
411 109 : TES_wake_clients (void)
412 : {
413 109 : uint64_t num = 1;
414 :
415 109 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
416 109 : for (struct TES_Client *client = TES_clients_head;
417 204 : NULL != client;
418 95 : client = client->next)
419 : {
420 : #ifdef __linux__
421 95 : if (-1 == client->esock)
422 0 : continue;
423 95 : GNUNET_assert (sizeof (num) ==
424 : write (client->esock,
425 : &num,
426 : sizeof (num)));
427 : #else
428 : if (-1 == client->esock_in)
429 : continue;
430 : GNUNET_assert (sizeof (num) ==
431 : write (client->esock_in,
432 : &num,
433 : sizeof (num)));
434 : #endif
435 : }
436 109 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
437 109 : }
438 :
439 :
440 : enum GNUNET_GenericReturnValue
441 3269 : TES_read_work (void *cls,
442 : TES_MessageDispatch dispatch)
443 : {
444 3269 : struct TES_Client *client = cls;
445 3269 : char *buf = client->iobuf;
446 3269 : size_t off = 0;
447 3269 : uint16_t msize = 0;
448 3269 : const struct GNUNET_MessageHeader *hdr = NULL;
449 : enum GNUNET_GenericReturnValue ret;
450 :
451 : do
452 : {
453 : ssize_t recv_size;
454 :
455 3269 : recv_size = recv (client->csock,
456 3269 : &buf[off],
457 : sizeof (client->iobuf) - off,
458 : 0);
459 3277 : if (-1 == recv_size)
460 : {
461 3 : if ( (0 == off) &&
462 0 : (EAGAIN == errno) )
463 0 : return GNUNET_NO;
464 3 : if ( (EINTR == errno) ||
465 0 : (EAGAIN == errno) )
466 : {
467 3 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG,
468 : "recv");
469 0 : continue;
470 : }
471 0 : if (ECONNRESET != errno)
472 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
473 : "recv");
474 0 : return GNUNET_SYSERR;
475 : }
476 3274 : if (0 == recv_size)
477 : {
478 : /* regular disconnect? */
479 38 : GNUNET_break_op (0 == off);
480 38 : return GNUNET_SYSERR;
481 : }
482 3236 : off += recv_size;
483 3237 : more:
484 3237 : msize = sizeof (*hdr); /* at least */
485 3237 : if (off < msize)
486 0 : continue;
487 3237 : hdr = (const struct GNUNET_MessageHeader *) buf;
488 3237 : msize = ntohs (hdr->size);
489 : #if 0
490 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
491 : "Received message of type %u with %u bytes\n",
492 : (unsigned int) ntohs (hdr->type),
493 : (unsigned int) msize);
494 : #endif
495 3237 : if (msize < sizeof (*hdr))
496 : {
497 0 : GNUNET_break_op (0);
498 0 : return GNUNET_SYSERR;
499 : }
500 3237 : } while (off < msize);
501 :
502 3237 : ret = dispatch (client,
503 : hdr);
504 3217 : if ( (GNUNET_OK != ret) ||
505 3217 : (off == msize) )
506 3216 : return ret;
507 1 : memmove (buf,
508 1 : &buf[msize],
509 : off - msize);
510 1 : off -= msize;
511 1 : goto more;
512 : }
513 :
514 :
515 : bool
516 3317 : TES_await_ready (struct TES_Client *client)
517 : {
518 : /* wait for reply with 1s timeout */
519 3317 : struct pollfd pfds[] = {
520 : {
521 3317 : .fd = client->csock,
522 : .events = POLLIN
523 : },
524 : {
525 : #ifdef __linux__
526 3317 : .fd = client->esock,
527 : #else
528 : .fd = client->esock_out,
529 : #endif
530 : .events = POLLIN
531 : },
532 : };
533 : int ret;
534 :
535 3317 : ret = poll (pfds,
536 : 2,
537 : -1);
538 3336 : if ( (-1 == ret) &&
539 0 : (EINTR != errno) )
540 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
541 : "poll");
542 9934 : for (int i = 0; i<2; i++)
543 : {
544 6661 : if (
545 : #ifdef __linux__
546 6661 : (pfds[i].fd == client->esock) &&
547 : #else
548 : (pfds[i].fd == client->esock_out) &&
549 : #endif
550 3332 : (POLLIN == pfds[i].revents) )
551 : {
552 : uint64_t num;
553 :
554 : #ifdef __linux__
555 60 : GNUNET_assert (sizeof (num) ==
556 : read (client->esock,
557 : &num,
558 : sizeof (num)));
559 : #else
560 : GNUNET_assert (sizeof (num) ==
561 : read (client->esock_out,
562 : &num,
563 : sizeof (num)));
564 : #endif
565 60 : return true;
566 : }
567 : }
568 3273 : return false;
569 : }
570 :
571 :
572 : /**
573 : * Main function of a worker thread that signs.
574 : *
575 : * @param cls the client we are working on
576 : * @return NULL
577 : */
578 : static void *
579 86 : sign_worker (void *cls)
580 : {
581 86 : struct TES_Client *client = cls;
582 :
583 86 : if (GNUNET_OK !=
584 86 : client->cb.init (client))
585 : {
586 0 : GNUNET_break (0);
587 0 : return NULL;
588 : }
589 3365 : while (! in_shutdown)
590 : {
591 3317 : if (TES_await_ready (client))
592 : {
593 60 : if (GNUNET_OK !=
594 60 : client->cb.updater (client))
595 0 : break;
596 : }
597 : else
598 : {
599 3257 : if (GNUNET_SYSERR ==
600 3272 : TES_read_work (client,
601 : client->cb.dispatch))
602 38 : break;
603 : }
604 : }
605 86 : GNUNET_break (0 == close (client->csock));
606 86 : client->csock = -1;
607 86 : return NULL;
608 : }
609 :
610 :
611 : /**
612 : * Clean up @a pos, joining the thread and closing the
613 : * file descriptors.
614 : *
615 : * @param[in] pos client to clean up
616 : */
617 : static void
618 86 : join_client (struct TES_Client *pos)
619 : {
620 : void *rval;
621 :
622 86 : GNUNET_CONTAINER_DLL_remove (TES_clients_head,
623 : TES_clients_tail,
624 : pos);
625 86 : GNUNET_break (0 ==
626 : pthread_join (pos->worker,
627 : &rval));
628 : #ifdef __linux__
629 86 : GNUNET_break (0 == close (pos->esock));
630 86 : pos->esock = -1;
631 : #else
632 : GNUNET_break (0 == close (pos->esock_in));
633 : pos->esock_in = -1;
634 : GNUNET_break (0 == close (pos->esock_out));
635 : pos->esock_out = -1;
636 : #endif
637 86 : GNUNET_free (pos);
638 86 : }
639 :
640 :
641 : /**
642 : * Task that listens for incoming clients.
643 : *
644 : * @param cls a `struct TES_Callbacks`
645 : */
646 : static void
647 86 : listen_job (void *cls)
648 : {
649 86 : const struct TES_Callbacks *cb = cls;
650 : int s;
651 : #ifdef __linux__
652 : int e;
653 : #else
654 : int e[2];
655 : #endif
656 : struct sockaddr_storage sa;
657 86 : socklen_t sa_len = sizeof (sa);
658 :
659 86 : listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
660 : unix_sock,
661 : &listen_job,
662 : cls);
663 86 : s = accept (GNUNET_NETWORK_get_fd (unix_sock),
664 : (struct sockaddr *) &sa,
665 : &sa_len);
666 86 : if (-1 == s)
667 : {
668 0 : bool st = ( (ENFILE == errno) ||
669 0 : (EMFILE == errno) );
670 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
671 : "accept");
672 0 : if (st)
673 : {
674 0 : GNUNET_SCHEDULER_cancel (listen_task);
675 0 : listen_task = NULL;
676 : }
677 0 : return;
678 : }
679 : #ifdef __linux__
680 86 : e = eventfd (0,
681 : EFD_CLOEXEC);
682 86 : if (-1 == e)
683 : {
684 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
685 : "eventfd");
686 0 : GNUNET_break (0 == close (s));
687 0 : return;
688 : }
689 : #else
690 : if (0 != pipe (e))
691 : {
692 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
693 : "pipe");
694 : GNUNET_break (0 == close (s));
695 : return;
696 : }
697 : #endif
698 : {
699 : struct TES_Client *client;
700 : struct TES_Client *nxt;
701 :
702 86 : client = GNUNET_new (struct TES_Client);
703 86 : client->cb = *cb;
704 86 : client->csock = s;
705 : #ifdef __linux__
706 86 : client->esock = e;
707 : #else
708 : client->esock_in = e[1];
709 : client->esock_out = e[0];
710 : #endif
711 86 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
712 86 : for (struct TES_Client *pos = TES_clients_head;
713 173 : NULL != pos;
714 87 : pos = nxt)
715 : {
716 87 : nxt = pos->next;
717 87 : if (-1 == pos->csock)
718 : {
719 3 : join_client (pos);
720 : }
721 : }
722 86 : GNUNET_CONTAINER_DLL_insert (TES_clients_head,
723 : TES_clients_tail,
724 : client);
725 86 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
726 86 : if (0 !=
727 86 : pthread_create (&client->worker,
728 : NULL,
729 : &sign_worker,
730 : client))
731 : {
732 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
733 : "pthread_create");
734 0 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
735 0 : GNUNET_CONTAINER_DLL_remove (TES_clients_head,
736 : TES_clients_tail,
737 : client);
738 0 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
739 0 : GNUNET_break (0 == close (client->csock));
740 : #ifdef __linux__
741 0 : GNUNET_break (0 == close (client->esock));
742 : #else
743 : GNUNET_break (0 == close (client->esock_in));
744 : GNUNET_break (0 == close (client->esock_out));
745 : #endif
746 0 : GNUNET_free (client);
747 : }
748 : }
749 : }
750 :
751 :
752 : int
753 62 : TES_listen_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
754 : const char *section,
755 : const struct TES_Callbacks *cb)
756 : {
757 : {
758 : char *pfn;
759 :
760 62 : if (GNUNET_OK !=
761 62 : GNUNET_CONFIGURATION_get_value_filename (cfg,
762 : section,
763 : "SM_PRIV_KEY",
764 : &pfn))
765 : {
766 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
767 : section,
768 : "SM_PRIV_KEY");
769 0 : return EXIT_NOTCONFIGURED;
770 : }
771 62 : if (GNUNET_SYSERR ==
772 62 : GNUNET_CRYPTO_eddsa_key_from_file (pfn,
773 : GNUNET_YES,
774 : &TES_smpriv.eddsa_priv))
775 : {
776 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
777 : section,
778 : "SM_PRIV_KEY",
779 : "Could not use file to persist private key");
780 0 : GNUNET_free (pfn);
781 0 : return EXIT_NOPERMISSION;
782 : }
783 62 : GNUNET_free (pfn);
784 62 : GNUNET_CRYPTO_eddsa_key_get_public (&TES_smpriv.eddsa_priv,
785 : &TES_smpub.eddsa_pub);
786 : }
787 :
788 62 : if (GNUNET_OK !=
789 62 : GNUNET_CONFIGURATION_get_value_filename (cfg,
790 : section,
791 : "UNIXPATH",
792 : &unixpath))
793 : {
794 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
795 : section,
796 : "UNIXPATH");
797 0 : return EXIT_NOTCONFIGURED;
798 : }
799 62 : GNUNET_assert (NULL != unixpath);
800 62 : unix_sock = TES_open_socket (unixpath);
801 62 : if (NULL == unix_sock)
802 : {
803 0 : GNUNET_free (unixpath);
804 0 : GNUNET_break (0);
805 0 : return EXIT_NOPERMISSION;
806 : }
807 : /* start job to accept incoming requests on 'sock' */
808 62 : listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
809 : unix_sock,
810 : &listen_job,
811 : (void *) cb);
812 62 : return 0;
813 : }
814 :
815 :
816 : void
817 62 : TES_listen_stop (void)
818 : {
819 : struct TES_Client *client;
820 :
821 62 : if (NULL != listen_task)
822 : {
823 62 : GNUNET_SCHEDULER_cancel (listen_task);
824 62 : listen_task = NULL;
825 : }
826 62 : if (NULL != unix_sock)
827 : {
828 62 : GNUNET_break (GNUNET_OK ==
829 : GNUNET_NETWORK_socket_close (unix_sock));
830 62 : unix_sock = NULL;
831 : }
832 62 : if (0 != unlink (unixpath))
833 : {
834 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
835 : "unlink",
836 : unixpath);
837 : }
838 62 : GNUNET_free (unixpath);
839 62 : in_shutdown = true;
840 62 : TES_wake_clients ();
841 62 : GNUNET_assert (0 == pthread_mutex_lock (&TES_clients_lock));
842 145 : while (NULL != (client = TES_clients_head))
843 83 : join_client (client);
844 62 : GNUNET_assert (0 == pthread_mutex_unlock (&TES_clients_lock));
845 62 : }
|