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:
| M | src/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);