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.
  *
  *  Copyright (C) 2002-2011 OpenVPN Technologies, Inc. <sales@openvpn.net>
  *
  *  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.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program (see the file COPYING included with this
  *  distribution); if not, write to the Free Software Foundation, Inc.,
  *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
  * 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)
 {
   void *data;
   ssize_t stat;
   int fd;
   struct mmap_stats ms;
 
   if (mmap_stats) /* already called? */
     return;
 
   /* verify that filename is not too long */
   if (strlen(fn) >= sizeof(mmap_fn))
     msg (M_FATAL, "mstats_open: filename too long");
 
   /* create file that will be memory mapped */
   fd = open (fn, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
   if (fd < 0)
     {
       msg (M_ERR, "mstats_open: cannot open: %s", fn);
       return;
     }
 
   /* 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))
     {
       msg (M_ERR, "mstats_open: write error: %s", fn);
       close(fd);
       return;
     }
 
   /* mmap the file */
   data = mmap(NULL, sizeof(struct mmap_stats), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
   if (data == MAP_FAILED)
     {
       msg (M_ERR, "mstats_open: write error: %s", fn);
       close(fd);
       return;
     }
 
   /* close the fd (mmap now controls the file) */
   if (close(fd))
     {
       msg (M_ERR, "mstats_open: close error: %s", fn);
     }
 
   /* save filename so we can delete it later */
   strcpy(mmap_fn, fn);
 
   /* save a global pointer to memory-mapped region */
   mmap_stats = (struct mmap_stats *)data;
 
   msg (M_INFO, "memstats data will be written to %s", fn);
 }
 
 void
 mstats_close(void)
 {
   if (mmap_stats)
     {
       mmap_stats->state = MSTATS_EXPIRED;
       if (munmap((void *)mmap_stats, sizeof(struct mmap_stats)))
 	msg (M_WARN | M_ERRNO, "mstats_close: munmap error");
       delete_file(mmap_fn);
       mmap_stats = NULL;
     }
 }
 
 #endif