Coverage Report

Created: 2025-07-11 06:28

/src/opensips/mem/rpm_mem.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Shared memory functions
3
 *
4
 * Copyright (C) 2001-2003 FhG Fokus
5
 *
6
 * This file is part of opensips, a free SIP server.
7
 *
8
 * opensips is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version
12
 *
13
 * opensips is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
21
 */
22
23
24
#include <stdlib.h>
25
26
#include "shm_mem.h"
27
#include "rpm_mem.h"
28
#include "../config.h"
29
#include "../globals.h"
30
31
#include <unistd.h>
32
#include <sys/mman.h>
33
#include <sys/types.h> /*open*/
34
#include <sys/stat.h>
35
#include <fcntl.h>
36
37
38
enum osips_mm mem_allocator_rpm = MM_NONE;
39
unsigned long rpm_mem_size = 0;
40
char *rpm_mem_file = RESTART_PERSISTENCY_MEM_FILE;
41
42
int set_rpm_mm(const char *mm_name)
43
0
{
44
#ifdef INLINE_ALLOC
45
  LM_NOTICE("this is an inlined allocator build (see opensips -V), "
46
            "cannot set a custom rpm allocator (%s)\n", mm_name);
47
  return 0;
48
#endif
49
50
0
  if (parse_mm(mm_name, &mem_allocator_rpm) < 0)
51
0
    return -1;
52
53
0
  return 0;
54
0
}
55
56
#ifndef INLINE_ALLOC
57
#ifdef DBG_MALLOC
58
void *(*gen_rpm_malloc)(void *blk, unsigned long size,
59
                        const char *file, const char *func, unsigned int line);
60
void *(*gen_rpm_malloc_unsafe)(void *blk, unsigned long size,
61
                        const char *file, const char *func, unsigned int line);
62
void *(*gen_rpm_realloc)(void *blk, void *p, unsigned long size,
63
                        const char *file, const char *func, unsigned int line);
64
void *(*gen_rpm_realloc_unsafe)(void *blk, void *p, unsigned long size,
65
                        const char *file, const char *func, unsigned int line);
66
void (*gen_rpm_free)(void *blk, void *p,
67
                      const char *file, const char *func, unsigned int line);
68
void (*gen_rpm_free_unsafe)(void *blk, void *p,
69
                      const char *file, const char *func, unsigned int line);
70
#else
71
void *(*gen_rpm_malloc)(void *blk, unsigned long size);
72
void *(*gen_rpm_malloc_unsafe)(void *blk, unsigned long size);
73
void *(*gen_rpm_realloc)(void *blk, void *p, unsigned long size);
74
void *(*gen_rpm_realloc_unsafe)(void *blk, void *p, unsigned long size);
75
void (*gen_rpm_free)(void *blk, void *p);
76
void (*gen_rpm_free_unsafe)(void *blk, void *p);
77
#endif
78
void (*gen_rpm_info)(void *blk, struct mem_info *info);
79
void (*gen_rpm_status)(void *blk);
80
unsigned long (*gen_rpm_get_size)(void *blk);
81
unsigned long (*gen_rpm_get_used)(void *blk);
82
unsigned long (*gen_rpm_get_rused)(void *blk);
83
unsigned long (*gen_rpm_get_mused)(void *blk);
84
unsigned long (*gen_rpm_get_free)(void *blk);
85
unsigned long (*gen_rpm_get_frags)(void *blk);
86
#endif
87
88
#if defined(HP_MALLOC)
89
stat_var *rpm_used;
90
stat_var *rpm_rused;
91
stat_var *rpm_frags;
92
#endif
93
94
#ifdef STATISTICS
95
stat_export_t rpm_stats[] = {
96
  {"rpm_total_size" ,     STAT_IS_FUNC,    (stat_var**)rpm_get_size  },
97
98
#if defined HP_MALLOC && defined INLINE_ALLOC
99
  {"rpm_used_size" ,     STAT_NO_RESET,               &rpm_used      },
100
  {"rpm_real_used_size" ,STAT_NO_RESET,               &rpm_rused     },
101
  {"rpm_fragments" ,     STAT_NO_RESET,               &rpm_frags     },
102
#else
103
  /* for HP_MALLOC, these still need to be edited to stats @ startup */
104
  {"rpm_used_size" ,      STAT_IS_FUNC,    (stat_var**)rpm_get_used  },
105
  {"rpm_real_used_size" , STAT_IS_FUNC,    (stat_var**)rpm_get_rused },
106
  {"rpm_fragments" ,      STAT_IS_FUNC,    (stat_var**)rpm_get_frags },
107
#endif
108
109
  {"rpm_max_used_size" ,  STAT_IS_FUNC,    (stat_var**)rpm_get_mused },
110
  {"rpm_free_size" ,      STAT_IS_FUNC,    (stat_var**)rpm_get_free  },
111
  {0,0,0}
112
};
113
#endif
114
115
void rpm_mem_destroy(void);
116
117
struct rpm_key {
118
  str key;
119
  void *value;
120
  struct rpm_key *next;
121
};
122
gen_lock_t *rpm_keys_lock;
123
124
struct _rpm_map_block {
125
  unsigned magic;           /* magic code used to check if file is valid -
126
                       should match - RPM_MAGIC_CODE */
127
  unsigned long size;         /* size of the block */
128
  enum osips_mm alloc;        /* allocator type */
129
  void *mapped_address;       /* address where file should be mapped */
130
  void *block_address;        /* block where the OpenSIPS memory starts */
131
  struct rpm_key *keys;       /* pointer to keys */
132
} __attribute__((__packed__)) *rpm_map_block = NULL;
133
134
135
#if defined F_MALLOC || defined Q_MALLOC
136
gen_lock_t *rpmem_lock;
137
#endif
138
139
#ifdef HP_MALLOC
140
gen_lock_t *rpmem_locks;
141
#endif
142
143
static void* rpm_mempool=INVALID_MAP;
144
void *rpm_block=NULL;
145
146
#if !defined INLINE_ALLOC && defined HP_MALLOC
147
/* startup optimization */
148
int rpm_use_global_lock;
149
#endif
150
151
int rpm_mem_init_allocs(void)
152
0
{
153
#ifdef HP_MALLOC
154
  int i;
155
#endif
156
157
0
#ifndef INLINE_ALLOC
158
0
  if (mem_allocator_rpm == MM_NONE)
159
0
    mem_allocator_rpm = mem_allocator;
160
161
#ifdef HP_MALLOC
162
  if (mem_allocator_rpm == MM_HP_MALLOC
163
          || mem_allocator_rpm == MM_HP_MALLOC_DBG) {
164
    rpm_stats[3].flags = STAT_NO_RESET;
165
    rpm_stats[3].stat_pointer = &rpm_used;
166
    rpm_stats[4].flags = STAT_NO_RESET;
167
    rpm_stats[4].stat_pointer = &rpm_rused;
168
    rpm_stats[5].flags = STAT_NO_RESET;
169
    rpm_stats[5].stat_pointer = &rpm_frags;
170
  } else {
171
    rpm_use_global_lock = 1;
172
  }
173
#endif
174
175
0
  switch (mem_allocator_rpm) {
176
#ifdef F_MALLOC
177
  case MM_F_MALLOC:
178
    gen_rpm_malloc         = (osips_block_malloc_f)fm_malloc;
179
    gen_rpm_malloc_unsafe  = (osips_block_malloc_f)fm_malloc;
180
    gen_rpm_realloc        = (osips_block_realloc_f)fm_realloc;
181
    gen_rpm_realloc_unsafe = (osips_block_realloc_f)fm_realloc;
182
    gen_rpm_free           = (osips_block_free_f)fm_free;
183
    gen_rpm_free_unsafe    = (osips_block_free_f)fm_free;
184
    gen_rpm_info           = (osips_mem_info_f)fm_info;
185
    gen_rpm_status         = (osips_mem_status_f)fm_status;
186
    gen_rpm_get_size       = (osips_get_mmstat_f)fm_get_size;
187
    gen_rpm_get_used       = (osips_get_mmstat_f)fm_get_used;
188
    gen_rpm_get_rused      = (osips_get_mmstat_f)fm_get_real_used;
189
    gen_rpm_get_mused      = (osips_get_mmstat_f)fm_get_max_real_used;
190
    gen_rpm_get_free       = (osips_get_mmstat_f)fm_get_free;
191
    gen_rpm_get_frags      = (osips_get_mmstat_f)fm_get_frags;
192
    break;
193
#endif
194
0
#ifdef Q_MALLOC
195
0
  case MM_Q_MALLOC:
196
0
    gen_rpm_malloc         = (osips_block_malloc_f)qm_malloc;
197
0
    gen_rpm_malloc_unsafe  = (osips_block_malloc_f)qm_malloc;
198
0
    gen_rpm_realloc        = (osips_block_realloc_f)qm_realloc;
199
0
    gen_rpm_realloc_unsafe = (osips_block_realloc_f)qm_realloc;
200
0
    gen_rpm_free           = (osips_block_free_f)qm_free;
201
0
    gen_rpm_free_unsafe    = (osips_block_free_f)qm_free;
202
0
    gen_rpm_info           = (osips_mem_info_f)qm_info;
203
0
    gen_rpm_status         = (osips_mem_status_f)qm_status;
204
0
    gen_rpm_get_size       = (osips_get_mmstat_f)qm_get_size;
205
0
    gen_rpm_get_used       = (osips_get_mmstat_f)qm_get_used;
206
0
    gen_rpm_get_rused      = (osips_get_mmstat_f)qm_get_real_used;
207
0
    gen_rpm_get_mused      = (osips_get_mmstat_f)qm_get_max_real_used;
208
0
    gen_rpm_get_free       = (osips_get_mmstat_f)qm_get_free;
209
0
    gen_rpm_get_frags      = (osips_get_mmstat_f)qm_get_frags;
210
0
    break;
211
0
#endif
212
#ifdef HP_MALLOC
213
  case MM_HP_MALLOC:
214
    gen_rpm_malloc         = (osips_block_malloc_f)hp_rpm_malloc;
215
    gen_rpm_malloc_unsafe  = (osips_block_malloc_f)hp_rpm_malloc_unsafe;
216
    gen_rpm_realloc        = (osips_block_realloc_f)hp_rpm_realloc;
217
    gen_rpm_realloc_unsafe = (osips_block_realloc_f)hp_rpm_realloc_unsafe;
218
    gen_rpm_free           = (osips_block_free_f)hp_rpm_free;
219
    gen_rpm_free_unsafe    = (osips_block_free_f)hp_rpm_free_unsafe;
220
    gen_rpm_info           = (osips_mem_info_f)hp_info;
221
    gen_rpm_status         = (osips_mem_status_f)hp_status;
222
    gen_rpm_get_size       = (osips_get_mmstat_f)hp_rpm_get_size;
223
    gen_rpm_get_used       = (osips_get_mmstat_f)hp_rpm_get_used;
224
    gen_rpm_get_rused      = (osips_get_mmstat_f)hp_rpm_get_real_used;
225
    gen_rpm_get_mused      = (osips_get_mmstat_f)hp_rpm_get_max_real_used;
226
    gen_rpm_get_free       = (osips_get_mmstat_f)hp_rpm_get_free;
227
    gen_rpm_get_frags      = (osips_get_mmstat_f)hp_rpm_get_frags;
228
    break;
229
#endif
230
#ifdef DBG_MALLOC
231
#ifdef F_MALLOC
232
  case MM_F_MALLOC_DBG:
233
    gen_rpm_malloc         = (osips_block_malloc_f)fm_malloc_dbg;
234
    gen_rpm_malloc_unsafe  = (osips_block_malloc_f)fm_malloc_dbg;
235
    gen_rpm_realloc        = (osips_block_realloc_f)fm_realloc_dbg;
236
    gen_rpm_realloc_unsafe = (osips_block_realloc_f)fm_realloc_dbg;
237
    gen_rpm_free           = (osips_block_free_f)fm_free_dbg;
238
    gen_rpm_free_unsafe    = (osips_block_free_f)fm_free_dbg;
239
    gen_rpm_info           = (osips_mem_info_f)fm_info;
240
    gen_rpm_status         = (osips_mem_status_f)fm_status_dbg;
241
    gen_rpm_get_size       = (osips_get_mmstat_f)fm_get_size;
242
    gen_rpm_get_used       = (osips_get_mmstat_f)fm_get_used;
243
    gen_rpm_get_rused      = (osips_get_mmstat_f)fm_get_real_used;
244
    gen_rpm_get_mused      = (osips_get_mmstat_f)fm_get_max_real_used;
245
    gen_rpm_get_free       = (osips_get_mmstat_f)fm_get_free;
246
    gen_rpm_get_frags      = (osips_get_mmstat_f)fm_get_frags;
247
    break;
248
#endif
249
#ifdef Q_MALLOC
250
  case MM_Q_MALLOC_DBG:
251
    gen_rpm_malloc         = (osips_block_malloc_f)qm_malloc_dbg;
252
    gen_rpm_malloc_unsafe  = (osips_block_malloc_f)qm_malloc_dbg;
253
    gen_rpm_realloc        = (osips_block_realloc_f)qm_realloc_dbg;
254
    gen_rpm_realloc_unsafe = (osips_block_realloc_f)qm_realloc_dbg;
255
    gen_rpm_free           = (osips_block_free_f)qm_free_dbg;
256
    gen_rpm_free_unsafe    = (osips_block_free_f)qm_free_dbg;
257
    gen_rpm_info           = (osips_mem_info_f)qm_info;
258
    gen_rpm_status         = (osips_mem_status_f)qm_status_dbg;
259
    gen_rpm_get_size       = (osips_get_mmstat_f)qm_get_size;
260
    gen_rpm_get_used       = (osips_get_mmstat_f)qm_get_used;
261
    gen_rpm_get_rused      = (osips_get_mmstat_f)qm_get_real_used;
262
    gen_rpm_get_mused      = (osips_get_mmstat_f)qm_get_max_real_used;
263
    gen_rpm_get_free       = (osips_get_mmstat_f)qm_get_free;
264
    gen_rpm_get_frags      = (osips_get_mmstat_f)qm_get_frags;
265
    break;
266
#endif
267
#ifdef HP_MALLOC
268
  case MM_HP_MALLOC_DBG:
269
    gen_rpm_malloc         = (osips_block_malloc_f)hp_rpm_malloc_dbg;
270
    gen_rpm_malloc_unsafe  = (osips_block_malloc_f)hp_rpm_malloc_unsafe_dbg;
271
    gen_rpm_realloc        = (osips_block_realloc_f)hp_rpm_realloc_dbg;
272
    gen_rpm_realloc_unsafe = (osips_block_realloc_f)hp_rpm_realloc_unsafe_dbg;
273
    gen_rpm_free           = (osips_block_free_f)hp_rpm_free_dbg;
274
    gen_rpm_free_unsafe    = (osips_block_free_f)hp_rpm_free_unsafe_dbg;
275
    gen_rpm_info           = (osips_mem_info_f)hp_info;
276
    gen_rpm_status         = (osips_mem_status_f)hp_status_dbg;
277
    gen_rpm_get_size       = (osips_get_mmstat_f)hp_rpm_get_size;
278
    gen_rpm_get_used       = (osips_get_mmstat_f)hp_rpm_get_used;
279
    gen_rpm_get_rused      = (osips_get_mmstat_f)hp_rpm_get_real_used;
280
    gen_rpm_get_mused      = (osips_get_mmstat_f)hp_rpm_get_max_real_used;
281
    gen_rpm_get_free       = (osips_get_mmstat_f)hp_rpm_get_free;
282
    gen_rpm_get_frags      = (osips_get_mmstat_f)hp_rpm_get_frags;
283
    break;
284
#endif
285
#endif
286
0
  default:
287
0
    LM_ERR("current build does not include support for "
288
0
           "selected allocator (%s)\n", mm_str(mem_allocator_rpm));
289
0
    return -1;
290
0
  }
291
292
0
#endif
293
294
  /* store locks in sharem memory, so we don't have to clean them up */
295
#ifdef HP_MALLOC
296
  /* lock_alloc cannot be used yet! */
297
  rpmem_locks = shm_malloc(HP_TOTAL_HASH_SIZE * sizeof *rpmem_locks);
298
  if (!rpmem_locks) {
299
    LM_CRIT("could not allocate the rp shm lock array\n");
300
    return -1;
301
  }
302
303
  for (i = 0; i < HP_TOTAL_HASH_SIZE; i++)
304
    if (!lock_init(&rpmem_locks[i])) {
305
      LM_CRIT("could not initialize rp lock\n");
306
      return -1;
307
    }
308
#endif
309
310
0
#if defined F_MALLOC || defined Q_MALLOC
311
0
  rpmem_lock = shm_malloc(sizeof *rpmem_lock);
312
0
  if (!rpmem_lock) {
313
0
    LM_CRIT("could not allocate the rp shm lock\n");
314
0
    return -1;
315
0
  }
316
317
0
  if (!lock_init(rpmem_lock)) {
318
0
    LM_CRIT("could not initialize rp lock\n");
319
0
    return -1;
320
0
  }
321
0
#endif
322
323
0
  rpm_keys_lock = shm_malloc(sizeof *rpm_keys_lock);
324
0
  if (!rpm_keys_lock) {
325
0
    LM_CRIT("could not allocate the rpm keys lock\n");
326
0
    return -1;
327
0
  }
328
329
0
  if (!lock_init(rpm_keys_lock)) {
330
0
    LM_CRIT("could not initialize rpm keys lock\n");
331
0
    return -1;
332
0
  }
333
#if defined HP_MALLOC && defined INLINE_ALLOC
334
  hp_init_rpm_statistics(rpm_block);
335
#endif
336
337
0
  return 0;
338
0
}
339
340
int rpm_mem_init_mallocs(void* mempool, unsigned long pool_size)
341
0
{
342
0
#ifndef INLINE_ALLOC
343
0
  if (mem_allocator_rpm == MM_NONE)
344
0
    mem_allocator_rpm = mem_allocator;
345
0
#endif
346
347
#ifdef INLINE_ALLOC
348
#if defined F_MALLOC
349
  rpm_block = fm_malloc_init(mempool, pool_size, "rpm");
350
#elif defined Q_MALLOC
351
  rpm_block = qm_malloc_init(mempool, pool_size, "rpm");
352
#elif defined HP_MALLOC
353
  rpm_block = hp_pkg_malloc_init(mempool, pool_size, "rpm");
354
#endif
355
#else
356
0
  switch (mem_allocator_rpm) {
357
#ifdef F_MALLOC
358
  case MM_F_MALLOC:
359
    rpm_block = fm_malloc_init(mempool, pool_size, "rpm");
360
    break;
361
#endif
362
0
#ifdef Q_MALLOC
363
0
  case MM_Q_MALLOC:
364
0
    rpm_block = qm_malloc_init(mempool, pool_size, "rpm");
365
0
    break;
366
0
#endif
367
#ifdef HP_MALLOC
368
  case MM_HP_MALLOC:
369
    rpm_block = hp_shm_malloc_init(mempool, pool_size, "rpm");
370
    break;
371
#endif
372
#ifdef DBG_MALLOC
373
#ifdef F_MALLOC
374
  case MM_F_MALLOC_DBG:
375
    rpm_block = fm_malloc_init(mempool, pool_size, "rpm");
376
    break;
377
#endif
378
#ifdef Q_MALLOC
379
  case MM_Q_MALLOC_DBG:
380
    rpm_block = qm_malloc_init(mempool, pool_size, "rpm");
381
    break;
382
#endif
383
#ifdef HP_MALLOC
384
  case MM_HP_MALLOC_DBG:
385
    rpm_block = hp_pkg_malloc_init(mempool, pool_size, "rpm");
386
    break;
387
#endif
388
#endif
389
0
  default:
390
0
    LM_ERR("current build does not include support for "
391
0
           "selected allocator (%s)\n", mm_str(mem_allocator_rpm));
392
0
    return -1;
393
0
  }
394
395
0
#endif
396
397
0
  if (!rpm_block){
398
0
    LM_CRIT("could not initialize restart persistent malloc\n");
399
0
    return -1;
400
0
  }
401
402
0
  LM_DBG("success\n");
403
404
0
  return 0;
405
0
}
406
407
/* Loads a restart persistency file in memory
408
 * Returns 0 if load is success, -1 on error, or 1 if the cache is invalid */
409
int load_rpm_file(void)
410
0
{
411
0
  struct _rpm_map_block tmp;
412
0
  int fd, ret;
413
0
  int bytes_needed, bytes_read;
414
0
  enum osips_mm alloc;
415
416
0
  fd = open(rpm_mem_file, O_RDWR);
417
0
  if (fd < 0) {
418
0
    LM_ERR("cannot open restart persistency file: %s\n", rpm_mem_file);
419
0
    return -1;
420
0
  }
421
  /* read the block */
422
0
  bytes_read = 0;
423
0
  bytes_needed = sizeof(tmp);
424
0
  do {
425
0
    ret = read(fd, ((char *)&tmp) + bytes_read, bytes_needed);
426
0
    if (ret < 0) {
427
0
      if (errno == EINTR)
428
0
        continue;
429
0
      LM_ERR("could not read from restart persistency file: %s (%d: %s)\n",
430
0
          rpm_mem_file, errno, strerror(errno));
431
0
      close(fd);
432
0
      return -1;
433
0
    }
434
0
    bytes_read += ret;
435
0
    bytes_needed -= ret;
436
0
  } while(bytes_needed > 0);
437
438
  /* check if the file is a valid cache file */
439
0
  if (tmp.magic != RPM_MAGIC_CODE) {
440
0
    LM_WARN("restart persistency file %s does not have the expected magic: %u\n",
441
0
        rpm_mem_file, tmp.magic);
442
0
    goto recreate;
443
0
  }
444
0
  if (tmp.size != rpm_mem_size) {
445
0
    LM_WARN("restart persistency file %s size=%lu != expected size=%lu\n",
446
0
        rpm_mem_file, tmp.size, rpm_mem_size);
447
0
    goto recreate;
448
0
  }
449
450
#ifdef INLINE_ALLOC
451
  alloc = MM_NONE;
452
#else
453
0
  if (mem_allocator_rpm != MM_NONE)
454
0
    alloc = mem_allocator;
455
0
  else
456
0
    alloc = mem_allocator_rpm;
457
0
#endif
458
459
0
  if (tmp.alloc != alloc) {
460
0
    LM_WARN("restart persistency file %s different alloc==%d != expected=%d\n",
461
0
        rpm_mem_file, tmp.alloc, alloc);
462
0
    goto recreate;
463
0
  }
464
465
  /* rewind the head of the fd */
466
0
  lseek(fd, 0, SEEK_SET);
467
468
  /* it all looks good here - lets map it */
469
0
  rpm_mempool = shm_getmem(fd, tmp.mapped_address, rpm_mem_size);
470
0
  if (rpm_mempool == INVALID_MAP) {
471
0
    LM_CRIT("could not map persistency file  %s at expected location: %p\n",
472
0
        rpm_mem_file, tmp.mapped_address);
473
0
    goto recreate;
474
0
  }
475
0
  close(fd);
476
477
0
  rpm_block = tmp.block_address;
478
0
  rpm_map_block = rpm_mempool;
479
0
  if (rpm_mem_init_allocs() < 0) {
480
0
    rpm_mem_destroy();
481
0
    return 1;
482
0
  }
483
484
0
  return 0;
485
486
0
recreate:
487
0
  close(fd);
488
0
  return 1;
489
0
}
490
491
492
int init_rpm_mallocs(void)
493
0
{
494
0
  struct stat fst;
495
0
  int n, fd;
496
497
  /* if any of the rpm settings is set, then we should turn rpm_enabled on */
498
  /* if no custom memory was set, then use the shm size */
499
0
  if (!rpm_mem_size)
500
0
    rpm_mem_size = shm_mem_size;
501
502
0
  LM_INFO("using %ld Mb of restart persistent shared memory\n",
503
0
      rpm_mem_size/1024/1024);
504
505
  /* check if the file exists */
506
0
  n = stat(rpm_mem_file, &fst);
507
0
  if (n == 0) {
508
    /* check the size of the file */
509
0
    if (fst.st_size != rpm_mem_size) {
510
0
      LM_WARN("restart persistency cache (%s) size %ld is different than "
511
0
          "the size we are running with %ld: creating a new cache!\n",
512
0
          rpm_mem_file, (long)fst.st_size, rpm_mem_size);
513
0
    } else if (load_rpm_file() == 0)
514
0
      return 0; /* memblock loaded just fine */
515
0
    LM_INFO("restart persistent cache is invalid: creating a new one!\n");
516
0
  } else if (errno != ENOENT) {
517
0
    LM_ERR("could not access file (or path) to the cache: %s (%d: %s)\n",
518
0
        rpm_mem_file, errno, strerror(errno));
519
0
    return -1;
520
0
  } else
521
0
    LM_DBG("restart persistent cache does not exist: %s. Creating it!\n",
522
0
        rpm_mem_file);
523
524
0
  fd = open(rpm_mem_file, O_RDWR|O_CREAT|O_TRUNC, 0600);
525
0
  if (fd < 0) {
526
0
    LM_ERR("could not create the restart persistency memory file %s (%d: %s)\n",
527
0
        rpm_mem_file, errno, strerror(errno));
528
0
    return -1;
529
0
  }
530
0
  lseek(fd, 0, SEEK_SET);
531
0
  if (ftruncate(fd, rpm_mem_size) < 0) {
532
0
    LM_ERR("could not set restart persistency file size %lu\n", rpm_mem_size);
533
0
    goto error;
534
0
  }
535
536
  /* all good - let's map the file */
537
0
  for (n = 0; n < RPM_MAP_RETRIES; n++) {
538
0
    rpm_mempool = shm_getmem(fd, RPM_MAP_ADDRESS + n * rpm_mem_size,
539
0
        rpm_mem_size);
540
0
    if (rpm_mempool != INVALID_MAP)
541
0
      break;
542
0
    LM_WARN("could not map file at address %p - tried %d times\n",
543
0
        RPM_MAP_ADDRESS + n * rpm_mem_size, n);
544
0
  }
545
0
  if (n == RPM_MAP_RETRIES) {
546
    /* last chance: map it anywhere and hope it will be available next
547
     * time */
548
0
    rpm_mempool = shm_getmem(fd, NULL, rpm_mem_size);
549
0
    if (rpm_mempool == INVALID_MAP) {
550
0
      LM_CRIT("could not find available memory zone for restart persistent file!\n");
551
0
      goto error;
552
0
    }
553
0
  }
554
0
  close(fd);
555
556
  /* finally, we've got a mempool - populate the block */
557
0
  rpm_map_block = rpm_mempool;
558
0
  memset(rpm_mempool, 0, sizeof(*rpm_map_block));
559
560
0
  rpm_map_block->magic = RPM_MAGIC_CODE;
561
0
  rpm_map_block->size = rpm_mem_size;
562
0
  rpm_map_block->mapped_address = rpm_mempool;
563
0
  rpm_map_block->block_address = (char *)rpm_map_block + sizeof(*rpm_map_block);
564
565
0
  if (rpm_mem_init_mallocs(rpm_map_block->block_address,
566
0
      rpm_mem_size - sizeof(*rpm_map_block)) < 0) {
567
0
    rpm_mem_destroy();
568
0
    return -1;
569
0
  }
570
  /* update in case of realigned */
571
0
  rpm_map_block->block_address = rpm_block;
572
573
0
  if (rpm_mem_init_allocs() < 0) {
574
0
    rpm_mem_destroy();
575
0
    return -1;
576
0
  }
577
578
0
  return 0;
579
580
0
error:
581
0
  close(fd);
582
0
  return -1;
583
0
}
584
585
void rpm_relmem(void *mempool, unsigned long size)
586
0
{
587
0
  if (mempool && (mempool!=INVALID_MAP))
588
0
    munmap(mempool, size);
589
0
}
590
591
void rpm_mem_destroy(void)
592
0
{
593
#ifdef HP_MALLOC
594
  int j;
595
#endif
596
0
  if (0
597
0
#if defined F_MALLOC || defined Q_MALLOC
598
0
    || rpmem_lock
599
0
#endif
600
#ifdef HP_MALLOC
601
    || rpmem_locks
602
#endif
603
0
  ) {
604
0
  #if defined F_MALLOC || defined Q_MALLOC
605
0
    if (rpmem_lock) {
606
0
      LM_DBG("destroying the shared memory lock\n");
607
0
      lock_destroy(rpmem_lock); /* we don't need to dealloc it*/
608
0
      rpmem_lock = NULL;
609
0
    }
610
0
  #endif
611
612
  #if defined HP_MALLOC
613
    if (rpmem_locks) {
614
      for (j = 0; j < HP_TOTAL_HASH_SIZE; j++)
615
        lock_destroy(&rpmem_locks[j]);
616
      rpmem_locks = NULL;
617
    }
618
  #endif
619
0
  }
620
0
  rpm_relmem(rpm_mempool, rpm_mem_size);
621
0
  rpm_mempool=INVALID_MAP;
622
0
  rpm_block = NULL;
623
0
}
624
625
int rpm_init_mem(void)
626
0
{
627
0
  if (rpm_mempool==INVALID_MAP) {
628
    /* memory pool not yet initialized */
629
0
    if (init_rpm_mallocs() < 0) {
630
0
      LM_ERR("could not initialize restart persistent memory!\n");
631
0
      rpm_mempool = 0;
632
0
      return -1;
633
0
    }
634
0
  }
635
0
  if (rpm_mempool == 0) {
636
    /* memory pool could not be init */
637
0
    LM_DBG("restart persistency could not be initialized!\n");
638
0
    return -1;
639
0
  }
640
0
  return 0;
641
0
}
642
643
void *rpm_key_get(char *key)
644
0
{
645
0
  struct rpm_key *k;
646
0
  int len;
647
0
  void *ret = NULL;
648
649
0
  if (!rpm_map_block || !rpm_map_block->keys)
650
0
    return NULL;
651
652
0
  len = strlen(key);
653
0
  lock_get(rpm_keys_lock);
654
0
  for (k = rpm_map_block->keys; k; k = k->next)
655
0
    if (len == k->key.len && memcmp(k->key.s, key, len) == 0) {
656
0
      ret = k->value;
657
0
      goto end;
658
0
    }
659
0
end:
660
0
  lock_release(rpm_keys_lock);
661
0
  return ret;
662
0
}
663
664
int rpm_key_set(char *key, void *val)
665
0
{
666
0
  struct rpm_key *k;
667
0
  int len;
668
669
0
  if (!rpm_map_block)
670
0
    return -2;
671
672
0
  len = strlen(key);
673
0
  lock_get(rpm_keys_lock);
674
0
  for (k = rpm_map_block->keys; k; k = k->next)
675
0
    if (len == k->key.len && memcmp(k->key.s, key, len) == 0)
676
0
      break;
677
678
0
  if (k != NULL) {
679
0
    k->value = val;
680
0
    lock_release(rpm_keys_lock);
681
0
    return 0;
682
0
  }
683
  /* key does not exist - add it now */
684
0
  k = rpm_malloc(sizeof(*k) + len);
685
0
  if (!k) {
686
0
    LM_ERR("could not add mem for rp key!\n");
687
0
    lock_release(rpm_keys_lock);
688
0
    return -1;
689
0
  }
690
0
  k->key.s = (char *)(k+1);
691
0
  memcpy(k->key.s, key, len);
692
0
  k->key.len = len;
693
0
  k->value = val;
694
0
  k->next = rpm_map_block->keys;
695
0
  rpm_map_block->keys = k;
696
0
  lock_release(rpm_keys_lock);
697
0
  return 0;
698
0
}
699
700
int rpm_key_del(char *key)
701
0
{
702
0
  struct rpm_key *k, *p;
703
0
  int len;
704
705
0
  if (!rpm_map_block)
706
0
    return -2;
707
0
  if (!rpm_map_block->keys)
708
0
    return -1;
709
710
0
  len = strlen(key);
711
0
  lock_get(rpm_keys_lock);
712
0
  for (p = NULL, k = rpm_map_block->keys; k; p = k, k = k->next)
713
0
    if (len == k->key.len && memcmp(k->key.s, key, len) == 0)
714
0
      break;
715
0
  if (!k) {
716
0
    LM_DBG("could not find key %s\n", key);
717
0
    lock_release(rpm_keys_lock);
718
0
    return -1;
719
0
  }
720
0
  if (!p) {
721
    /* first element */
722
0
    rpm_map_block->keys = k->next;
723
0
  } else {
724
0
    p->next = k->next;
725
0
  }
726
0
  lock_release(rpm_keys_lock);
727
0
  rpm_free(k);
728
0
  return 0;
729
0
}