exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 9e9941a182d046afe3c7ce7ae459981dc757ca40
parent 77f5a41ff26371cfc77644ba49c760e7778c142b
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat, 10 Oct 2026 22:37:13 +0200

mmap() instead of sendfile(), avoids holding extra FDs

Diffstat:
Msrc/mhd/mhd_spa.c | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 63 insertions(+), 6 deletions(-)

diff --git a/src/mhd/mhd_spa.c b/src/mhd/mhd_spa.c @@ -50,6 +50,17 @@ struct WebuiFile */ struct MHD_Response *responses[TALER_MHD_CT_MAX]; + /** + * mmap()'ed file contents served by the respective @e responses, + * NULL for empty files. Use munmap() to release. + */ + void *maps[TALER_MHD_CT_MAX]; + + /** + * Sizes of the respective @e maps. + */ + size_t map_sizes[TALER_MHD_CT_MAX]; + }; @@ -162,6 +173,8 @@ build_webui (void *cls, struct TALER_MHD_Spa *spa = cls; int fd; struct stat sb; + size_t size; + void *buf; struct MHD_Response *response; char *ext; const char *mime; @@ -195,6 +208,36 @@ build_webui (void *cls, GNUNET_break (0 == close (fd)); return GNUNET_SYSERR; } + if (SIZE_MAX < ((unsigned long long) sb.st_size)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "fstat-size", + dn); + GNUNET_break (0 == close (fd)); + return GNUNET_SYSERR; + } + size = (size_t) sb.st_size; + buf = NULL; + if (0 != size) + { + buf = mmap (NULL, + size, + PROT_READ, + MAP_SHARED, + fd, + 0); + if (MAP_FAILED == buf) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "mmap", + dn); + GNUNET_break (0 == close (fd)); + return GNUNET_SYSERR; + } + } + /* The mapping stays valid after the descriptor is closed; do not + hold one descriptor per file for the lifetime of the process. */ + GNUNET_break (0 == close (fd)); fn = GNUNET_strdup (slash + 1); ext = strrchr (fn, @@ -232,13 +275,14 @@ build_webui (void *cls, break; } - response = MHD_create_response_from_fd ( - sb.st_size, - fd /* FD now owned by MHD! */); + response = MHD_create_response_from_buffer_static (size, + buf); if (NULL == response) { - /* MHD did not take ownership of the FD after all */ - GNUNET_break (0 == close (fd)); + GNUNET_break (0); + if (NULL != buf) + GNUNET_break (0 == munmap (buf, + size)); GNUNET_free (fn); return GNUNET_SYSERR; } @@ -250,6 +294,9 @@ build_webui (void *cls, { GNUNET_break (0); MHD_destroy_response (response); + if (NULL != buf) + GNUNET_break (0 == munmap (buf, + size)); GNUNET_free (fn); return GNUNET_SYSERR; } @@ -293,10 +340,14 @@ build_webui (void *cls, } GNUNET_assert (NULL == w->responses[ct]); w->responses[ct] = response; + w->maps[ct] = buf; + w->map_sizes[ct] = size; } return GNUNET_OK; skip: - GNUNET_break (0 == close (fd)); + if (NULL != buf) + GNUNET_break (0 == munmap (buf, + size)); GNUNET_free (fn); return GNUNET_OK; } @@ -368,6 +419,12 @@ TALER_MHD_spa_free (struct TALER_MHD_Spa *spa) MHD_destroy_response (w->responses[ct]); w->responses[ct] = NULL; } + if (NULL != w->maps[ct]) + { + GNUNET_break (0 == munmap (w->maps[ct], + w->map_sizes[ct])); + w->maps[ct] = NULL; + } } GNUNET_free (w->path); GNUNET_free (w);