1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single TCP/UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2011 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25/*
26 * Maintain usage stats in a memory-mapped file
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#elif defined(_MSC_VER)
32#include "config-msvc.h"
33#endif
34
35#include "syshead.h"
36
37#if defined(ENABLE_MEMSTATS)
38
39#include <sys/mman.h>
40
41#include "error.h"
42#include "misc.h"
43#include "mstats.h"
44
45#include "memdbg.h"
46
47volatile struct mmap_stats *mmap_stats = NULL; /* GLOBAL */
48static char mmap_fn[128];
49
50void
51mstats_open(const char *fn)
52{
53  void *data;
54  ssize_t stat;
55  int fd;
56  struct mmap_stats ms;
57
58  if (mmap_stats) /* already called? */
59    return;
60
61  /* verify that filename is not too long */
62  if (strlen(fn) >= sizeof(mmap_fn))
63    msg (M_FATAL, "mstats_open: filename too long");
64
65  /* create file that will be memory mapped */
66  fd = open (fn, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
67  if (fd < 0)
68    {
69      msg (M_ERR, "mstats_open: cannot open: %s", fn);
70      return;
71    }
72
73  /* set the file to the correct size to contain a
74     struct mmap_stats, and zero it */
75  CLEAR(ms);
76  ms.state = MSTATS_ACTIVE;
77  stat = write(fd, &ms, sizeof(ms));
78  if (stat != sizeof(ms))
79    {
80      msg (M_ERR, "mstats_open: write error: %s", fn);
81      close(fd);
82      return;
83    }
84
85  /* mmap the file */
86  data = mmap(NULL, sizeof(struct mmap_stats), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
87  if (data == MAP_FAILED)
88    {
89      msg (M_ERR, "mstats_open: write error: %s", fn);
90      close(fd);
91      return;
92    }
93
94  /* close the fd (mmap now controls the file) */
95  if (close(fd))
96    {
97      msg (M_ERR, "mstats_open: close error: %s", fn);
98    }
99
100  /* save filename so we can delete it later */
101  strcpy(mmap_fn, fn);
102
103  /* save a global pointer to memory-mapped region */
104  mmap_stats = (struct mmap_stats *)data;
105
106  msg (M_INFO, "memstats data will be written to %s", fn);
107}
108
109void
110mstats_close(void)
111{
112  if (mmap_stats)
113    {
114      mmap_stats->state = MSTATS_EXPIRED;
115      if (munmap((void *)mmap_stats, sizeof(struct mmap_stats)))
116	msg (M_WARN | M_ERRNO, "mstats_close: munmap error");
117      platform_unlink(mmap_fn);
118      mmap_stats = NULL;
119    }
120}
121
122#endif
123