LCOV - code coverage report
Current view: top level - util - secmod_common.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 76.2 % 298 227
Test Date: 2026-10-01 12:53:39 Functions: 100.0 % 15 15

            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 : }
        

Generated by: LCOV version 2.0-1