src/openvpn/mstats.c
ffea644c
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
ffea644c
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
ffea644c
  */
 
 /*
  * Maintain usage stats in a memory-mapped file
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
ffea644c
 #include "syshead.h"
 
 #if defined(ENABLE_MEMSTATS)
 
 #include <sys/mman.h>
 
 #include "error.h"
 #include "misc.h"
 #include "mstats.h"
 
 #include "memdbg.h"
 
 volatile struct mmap_stats *mmap_stats = NULL; /* GLOBAL */
 static char mmap_fn[128];
 
 void
 mstats_open(const char *fn)
 {
81d882d5
     void *data;
     ssize_t stat;
     int fd;
     struct mmap_stats ms;
ffea644c
 
81d882d5
     if (mmap_stats) /* already called? */
     {
         return;
     }
ffea644c
 
81d882d5
     /* verify that filename is not too long */
     if (strlen(fn) >= sizeof(mmap_fn))
     {
         msg(M_FATAL, "mstats_open: filename too long");
     }
ffea644c
 
81d882d5
     /* create file that will be memory mapped */
     fd = open(fn, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
     if (fd < 0)
ffea644c
     {
81d882d5
         msg(M_ERR, "mstats_open: cannot open: %s", fn);
         return;
ffea644c
     }
 
81d882d5
     /* set the file to the correct size to contain a
      * struct mmap_stats, and zero it */
     CLEAR(ms);
     ms.state = MSTATS_ACTIVE;
     stat = write(fd, &ms, sizeof(ms));
     if (stat != sizeof(ms))
ffea644c
     {
81d882d5
         msg(M_ERR, "mstats_open: write error: %s", fn);
         close(fd);
         return;
ffea644c
     }
 
81d882d5
     /* mmap the file */
     data = mmap(NULL, sizeof(struct mmap_stats), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     if (data == MAP_FAILED)
ffea644c
     {
81d882d5
         msg(M_ERR, "mstats_open: write error: %s", fn);
         close(fd);
         return;
ffea644c
     }
 
81d882d5
     /* close the fd (mmap now controls the file) */
     if (close(fd))
ffea644c
     {
81d882d5
         msg(M_ERR, "mstats_open: close error: %s", fn);
ffea644c
     }
 
81d882d5
     /* save filename so we can delete it later */
     strcpy(mmap_fn, fn);
ffea644c
 
81d882d5
     /* save a global pointer to memory-mapped region */
     mmap_stats = (struct mmap_stats *)data;
ffea644c
 
81d882d5
     msg(M_INFO, "memstats data will be written to %s", fn);
ffea644c
 }
 
 void
 mstats_close(void)
 {
81d882d5
     if (mmap_stats)
ffea644c
     {
81d882d5
         mmap_stats->state = MSTATS_EXPIRED;
         if (munmap((void *)mmap_stats, sizeof(struct mmap_stats)))
         {
             msg(M_WARN | M_ERRNO, "mstats_close: munmap error");
         }
         platform_unlink(mmap_fn);
         mmap_stats = NULL;
ffea644c
     }
 }
 
81d882d5
 #endif /* if defined(ENABLE_MEMSTATS) */