2018-06-28 13:27:44 +02:00
|
|
|
/*
|
2019-02-22 16:57:28 +01:00
|
|
|
* Copyright (c) 2019 Joris Vink <joris@coders.se>
|
2018-06-28 13:27:44 +02:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
2019-03-29 19:25:27 +01:00
|
|
|
#include <stdint.h>
|
2018-06-28 13:45:04 +02:00
|
|
|
|
2018-06-28 13:27:44 +02:00
|
|
|
#include "kore.h"
|
|
|
|
|
|
|
|
/* cached filerefs expire after 30 seconds of inactivity. */
|
|
|
|
#define FILEREF_EXPIRATION (1000 * 30)
|
|
|
|
|
2019-03-21 10:17:08 +01:00
|
|
|
static void fileref_timer_prime(void);
|
2018-06-29 05:03:50 +02:00
|
|
|
static void fileref_drop(struct kore_fileref *);
|
2018-06-28 23:00:42 +02:00
|
|
|
static void fileref_soft_remove(struct kore_fileref *);
|
2018-06-28 13:27:44 +02:00
|
|
|
static void fileref_expiration_check(void *, u_int64_t);
|
|
|
|
|
|
|
|
static TAILQ_HEAD(, kore_fileref) refs;
|
|
|
|
static struct kore_pool ref_pool;
|
2019-03-21 10:17:08 +01:00
|
|
|
static struct kore_timer *ref_timer = NULL;
|
2018-06-28 13:27:44 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
kore_fileref_init(void)
|
|
|
|
{
|
|
|
|
TAILQ_INIT(&refs);
|
|
|
|
kore_pool_init(&ref_pool, "ref_pool", sizeof(struct kore_fileref), 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct kore_fileref *
|
2018-07-24 19:56:36 +02:00
|
|
|
kore_fileref_create(const char *path, int fd, off_t size, struct timespec *ts)
|
2018-06-28 13:27:44 +02:00
|
|
|
{
|
|
|
|
struct kore_fileref *ref;
|
|
|
|
|
2019-03-21 10:17:08 +01:00
|
|
|
fileref_timer_prime();
|
|
|
|
|
2018-06-28 13:27:44 +02:00
|
|
|
if ((ref = kore_fileref_get(path)) != NULL)
|
|
|
|
return (ref);
|
|
|
|
|
|
|
|
ref = kore_pool_get(&ref_pool);
|
|
|
|
|
|
|
|
ref->cnt = 1;
|
2018-06-28 23:00:42 +02:00
|
|
|
ref->flags = 0;
|
2018-06-28 13:27:44 +02:00
|
|
|
ref->size = size;
|
|
|
|
ref->path = kore_strdup(path);
|
2018-07-24 19:56:36 +02:00
|
|
|
ref->mtime_sec = ts->tv_sec;
|
|
|
|
ref->mtime = ((u_int64_t)(ts->tv_sec * 1000 + (ts->tv_nsec / 1000000)));
|
2018-06-28 13:27:44 +02:00
|
|
|
|
|
|
|
#if !defined(KORE_USE_PLATFORM_SENDFILE)
|
2018-07-24 19:56:36 +02:00
|
|
|
if ((uintmax_t)size> SIZE_MAX) {
|
|
|
|
kore_pool_put(&ref_pool, ref);
|
2018-06-28 13:27:44 +02:00
|
|
|
return (NULL);
|
2018-07-24 19:56:36 +02:00
|
|
|
}
|
2018-06-28 13:27:44 +02:00
|
|
|
|
|
|
|
ref->base = mmap(NULL, (size_t)size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
|
if (ref->base == MAP_FAILED)
|
|
|
|
fatal("net_send_file: mmap failed: %s", errno_s);
|
|
|
|
if (madvise(ref->base, (size_t)size, MADV_SEQUENTIAL) == -1)
|
|
|
|
fatal("net_send_file: madvise: %s", errno_s);
|
2018-06-29 05:03:50 +02:00
|
|
|
close(fd);
|
|
|
|
#else
|
|
|
|
ref->fd = fd;
|
2018-06-28 13:27:44 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(FILEREF_DEBUG)
|
|
|
|
kore_log(LOG_DEBUG, "ref:%p created", (void *)ref);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TAILQ_INSERT_TAIL(&refs, ref, list);
|
|
|
|
|
|
|
|
return (ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Caller must call kore_fileref_release() after kore_fileref_get() even
|
|
|
|
* if they don't end up using the ref.
|
|
|
|
*/
|
|
|
|
struct kore_fileref *
|
|
|
|
kore_fileref_get(const char *path)
|
|
|
|
{
|
2018-06-28 23:00:42 +02:00
|
|
|
struct stat st;
|
2018-06-28 13:27:44 +02:00
|
|
|
struct kore_fileref *ref;
|
2018-07-24 19:56:36 +02:00
|
|
|
u_int64_t mtime;
|
2018-06-28 13:27:44 +02:00
|
|
|
|
|
|
|
TAILQ_FOREACH(ref, &refs, list) {
|
|
|
|
if (!strcmp(ref->path, path)) {
|
2018-06-28 23:00:42 +02:00
|
|
|
if (stat(ref->path, &st) == -1) {
|
2018-07-28 22:27:38 +02:00
|
|
|
if (errno != ENOENT) {
|
|
|
|
kore_log(LOG_ERR, "stat(%s): %s",
|
|
|
|
ref->path, errno_s);
|
|
|
|
}
|
2018-06-28 23:00:42 +02:00
|
|
|
fileref_soft_remove(ref);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2018-07-24 19:56:36 +02:00
|
|
|
mtime = ((u_int64_t)(st.st_mtim.tv_sec * 1000 +
|
|
|
|
(st.st_mtim.tv_nsec / 1000000)));
|
|
|
|
|
|
|
|
if (ref->mtime != mtime) {
|
2018-06-28 23:00:42 +02:00
|
|
|
fileref_soft_remove(ref);
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
2018-06-28 13:27:44 +02:00
|
|
|
ref->cnt++;
|
|
|
|
#if defined(FILEREF_DEBUG)
|
|
|
|
kore_log(LOG_DEBUG, "ref:%p cnt:%d",
|
|
|
|
(void *)ref, ref->cnt);
|
|
|
|
#endif
|
|
|
|
TAILQ_REMOVE(&refs, ref, list);
|
|
|
|
TAILQ_INSERT_HEAD(&refs, ref, list);
|
|
|
|
return (ref);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
kore_fileref_release(struct kore_fileref *ref)
|
|
|
|
{
|
|
|
|
ref->cnt--;
|
|
|
|
|
|
|
|
#if defined(FILEREF_DEBUG)
|
|
|
|
kore_log(LOG_DEBUG, "ref:%p released cnt:%d", (void *)ref, ref->cnt);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ref->cnt < 0) {
|
|
|
|
fatal("kore_fileref_release: cnt < 0 (%p:%d)",
|
|
|
|
(void *)ref, ref->cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ref->cnt == 0) {
|
2018-06-29 05:03:50 +02:00
|
|
|
if (ref->flags & KORE_FILEREF_SOFT_REMOVED)
|
|
|
|
fileref_drop(ref);
|
|
|
|
else
|
|
|
|
ref->expiration = kore_time_ms() + FILEREF_EXPIRATION;
|
2018-06-28 13:27:44 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 10:17:08 +01:00
|
|
|
static void
|
|
|
|
fileref_timer_prime(void)
|
|
|
|
{
|
|
|
|
if (ref_timer != NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ref_timer = kore_timer_add(fileref_expiration_check, 10000, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2018-06-28 23:00:42 +02:00
|
|
|
static void
|
|
|
|
fileref_soft_remove(struct kore_fileref *ref)
|
|
|
|
{
|
2018-06-29 05:03:50 +02:00
|
|
|
if (ref->flags & KORE_FILEREF_SOFT_REMOVED)
|
|
|
|
fatal("fileref_soft_remove: %p already removed", (void *)ref);
|
|
|
|
|
|
|
|
#if defined(FILEREF_DEBUG)
|
|
|
|
kore_log(LOG_DEBUG, "ref:%p softremoved", (void *)ref);
|
|
|
|
#endif
|
|
|
|
|
2018-06-28 23:00:42 +02:00
|
|
|
TAILQ_REMOVE(&refs, ref, list);
|
|
|
|
ref->flags |= KORE_FILEREF_SOFT_REMOVED;
|
|
|
|
|
2018-06-29 05:03:50 +02:00
|
|
|
if (ref->cnt == 0)
|
|
|
|
fileref_drop(ref);
|
2018-06-28 23:00:42 +02:00
|
|
|
}
|
|
|
|
|
2018-06-28 13:27:44 +02:00
|
|
|
static void
|
|
|
|
fileref_expiration_check(void *arg, u_int64_t now)
|
|
|
|
{
|
|
|
|
struct kore_fileref *ref, *next;
|
|
|
|
|
|
|
|
for (ref = TAILQ_FIRST(&refs); ref != NULL; ref = next) {
|
|
|
|
next = TAILQ_NEXT(ref, list);
|
|
|
|
|
|
|
|
if (ref->cnt != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ref->expiration > now)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
#if defined(FILEREF_DEBUG)
|
|
|
|
kore_log(LOG_DEBUG, "ref:%p expired, removing", (void *)ref);
|
|
|
|
#endif
|
|
|
|
|
2018-06-29 05:03:50 +02:00
|
|
|
fileref_drop(ref);
|
|
|
|
}
|
2019-03-21 10:17:08 +01:00
|
|
|
|
|
|
|
if (TAILQ_EMPTY(&refs)) {
|
|
|
|
/* remove the timer. */
|
|
|
|
ref_timer->flags |= KORE_TIMER_ONESHOT;
|
|
|
|
ref_timer = NULL;
|
|
|
|
}
|
2018-06-29 05:03:50 +02:00
|
|
|
}
|
2018-06-28 23:00:42 +02:00
|
|
|
|
2018-06-29 05:03:50 +02:00
|
|
|
static void
|
|
|
|
fileref_drop(struct kore_fileref *ref)
|
|
|
|
{
|
|
|
|
#if defined(FILEREF_DEBUG)
|
|
|
|
kore_log(LOG_DEBUG, "ref:%p dropped", (void *)ref);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!(ref->flags & KORE_FILEREF_SOFT_REMOVED))
|
|
|
|
TAILQ_REMOVE(&refs, ref, list);
|
|
|
|
|
|
|
|
kore_free(ref->path);
|
2018-06-28 23:00:42 +02:00
|
|
|
|
|
|
|
#if !defined(KORE_USE_PLATFORM_SENDFILE)
|
2018-06-29 05:03:50 +02:00
|
|
|
(void)munmap(ref->base, ref->size);
|
|
|
|
#else
|
|
|
|
close(ref->fd);
|
2018-06-28 13:27:44 +02:00
|
|
|
#endif
|
2018-06-29 05:03:50 +02:00
|
|
|
kore_pool_put(&ref_pool, ref);
|
2018-06-28 13:27:44 +02:00
|
|
|
}
|