syslog-ng source
nvtable.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2002-2012 Balabit
3  * Copyright (c) 1998-2012 Balázs Scheidler
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * As an additional exemption you are allowed to compile & link against the
20  * OpenSSL libraries as published by the OpenSSL project. See the file
21  * COPYING for details.
22  *
23  */
24 
25 #ifndef PAYLOAD_H_INCLUDED
26 #define PAYLOAD_H_INCLUDED
27 
28 #include "syslog-ng.h"
29 #include "nvhandle-descriptors.h"
30 
31 typedef struct _NVTable NVTable;
32 typedef struct _NVRegistry NVRegistry;
33 typedef struct _NVIndexEntry NVIndexEntry;
34 typedef struct _NVEntry NVEntry;
35 typedef guint32 NVHandle;
36 typedef guint8 NVType;
37 typedef gboolean (*NVTableForeachFunc)(NVHandle handle, const gchar *name,
38  const gchar *value, gssize value_len,
39  NVType type, gpointer user_data);
40 typedef gboolean (*NVTableForeachEntryFunc)(NVHandle handle, NVEntry *entry, NVIndexEntry *index_entry,
41  gpointer user_data);
42 
43 #define NVHANDLE_MAX_VALUE ((NVHandle)-1)
44 
45 /* NVIndexEntry
46  * this represents an entry in the handle based lookup index, embedded in an NVTable.
47  *
48  * NOTE:
49  * The deserialization code (at least version 26) assumes that this can be
50  * represented by a pair of guint32 instances. It is reading the entire
51  * array back as such. Should you need to change the types here, please
52  * ensure that you also update the nvtable deserialization code.
53  */
55 {
57  guint32 ofs;
58 };
59 
61 {
62  /* number of static names that are statically allocated in each payload */
65  GHashTable *name_map;
67 };
68 
69 extern const gchar *null_string;
70 
71 void nv_registry_add_alias(NVRegistry *self, NVHandle handle, const gchar *alias);
72 void nv_registry_add_predefined(NVRegistry *self, NVHandle handle, const gchar *name);
73 void nv_registry_assert_next_handle(NVRegistry *self, NVHandle handle);
74 NVHandle nv_registry_get_handle(NVRegistry *self, const gchar *name);
75 NVHandle nv_registry_alloc_handle(NVRegistry *self, const gchar *name);
76 void nv_registry_set_handle_flags(NVRegistry *self, NVHandle handle, guint16 flags);
77 void nv_registry_foreach(NVRegistry *self, GHFunc callback, gpointer user_data);
78 NVRegistry *nv_registry_new(const gchar **static_names, guint32 nvhandle_max_value);
79 void nv_registry_free(NVRegistry *self);
80 
81 static inline guint16
82 nv_registry_get_handle_flags(NVRegistry *self, NVHandle handle)
83 {
84  NVHandleDesc *stored;
85 
86  if (G_UNLIKELY(!handle))
87  return 0;
88 
89  stored = &nvhandle_desc_array_index(self->names, handle - 1);
90  return stored->flags;
91 }
92 
93 static inline const gchar *
94 nv_registry_get_handle_name(NVRegistry *self, NVHandle handle, gssize *length)
95 {
96  NVHandleDesc *stored;
97 
98  if (G_UNLIKELY(!handle))
99  {
100  if (length)
101  *length = 4;
102  return "None";
103  }
104 
105  if (handle - 1 >= self->names->len)
106  {
107  if (length)
108  *length = 0;
109  return NULL;
110  }
111 
112  stored = &nvhandle_desc_array_index(self->names, handle - 1);
113  if (G_LIKELY(length))
114  *length = stored->name_len;
115  return stored->name;
116 }
117 
118 typedef struct _NVReferencedSlice
119 {
121  guint32 ofs;
122  guint32 len;
124 
125 /*
126  * Contains a name-value pair.
127  */
128 struct _NVEntry
129 {
130  /* negative offset, counting from string table top, e.g. start of the string is at @top + ofs */
131  union
132  {
133  struct
134  {
135  /* make sure you don't exceed 8 bits here. So if you want to add new
136  * bits, decrease the size of __bit_padding below */
137 
138  /* some of these bits were not zero initialized in the past, which we
139  * are fixing by the use of the NVT_SUPPORTS_UNSET flag in the NVTable
140  * header. If that flag is not present, we fix all but the originally
141  * existing bit fields to zero (both in current and legacy
142  * deserializers). We are using
143  * NVENTRY_FLAGS_DEFINED_IN_LEGACY_FORMATS as a bitmask to mask out
144  * "indirect" and "referenced" in the "flags" member below, which is
145  * unioned on the bitfield.
146  */
147  guint8 indirect: 1,
149  unset: 1,
152  };
153  guint8 flags;
154  };
155  guint8 name_len;
157 
158  /* NOTE: this field fills an empty padding byte, so if you are adding
159  * fields, please remove this. This is now zero initialized as of the
160  * first version of syslog-ng that contain this member. Earlier versions
161  * had an uninitialized padding byte here. */
162  guint8 __reserved;
163  guint32 alloc_len;
164  union
165  {
166  struct
167  {
168  guint32 value_len;
169  /* variable data, first the name of this entry, then the value, both are NUL terminated */
170  gchar data[];
172 
173  struct
174  {
176  guint32 ofs;
177  guint32 len;
178 
179  /* NOTE: this type field was promoted up into NVEntry, so we won't need
180  * the "type" field here, we are moving the value stored here in existing
181  * serialized messages in _update_entry() in logmsg-serialize-fixup.c. We
182  * might be able to reuse this byte once we drop compatibility with
183  * version 26 of the LogMessage serialization format.
184  *
185  * NOTE: we zero out this field upon reading and then reserializing a message.
186  */
187 
189 
190  gchar name[0];
192  };
193 };
194 
195 #define NV_ENTRY_DIRECT_HDR ((gsize) (&((NVEntry *) NULL)->vdirect.data))
196 #define NV_ENTRY_DIRECT_SIZE(name_len, value_len) ((value_len) + NV_ENTRY_DIRECT_HDR + (name_len) + 2)
197 #define NV_ENTRY_INDIRECT_HDR (sizeof(NVEntry))
198 #define NV_ENTRY_INDIRECT_SIZE(name_len) (NV_ENTRY_INDIRECT_HDR + name_len + 1)
199 
200 static inline const gchar *
201 nv_entry_get_name(NVEntry *self)
202 {
203  if (self->indirect)
204  return self->vindirect.name;
205  else
206  return self->vdirect.data;
207 }
208 
209 /*
210  * Contains a set of ordered name-value pairs.
211  *
212  * This struct is used to track a set of name-value pairs that make up
213  * a LogMessage structure. The storage layout is as concise as
214  * possible to make it possible to serialize this payload as a single
215  * writev() operation.
216  *
217  * Memory layout:
218  * =============
219  *
220  * || struct || static value offsets || dynamic value (id, offset) pairs || <free space> || stored (name, value) ||
221  *
222  * Name value area:
223  * - the name-value area grows down (e.g. lower addresses) from the end of the struct
224  * - name-value pairs are referenced by the offset counting down from the end of the struct
225  * - all NV pairs are positioned at 4 bytes boundary, so 32 bit variables in NVEntry
226  * can be accessed in an aligned manner
227  *
228  * Static value offsets:
229  * - a fixed size of guint32 array, containing 32 bit offsets for statically allocated entries
230  * - the handles for static values have a low value and they match the index in this array
231  *
232  * Dynamic values:
233  * - a dynamically sized NVIndexEntry array (contains ID + offset)
234  * - dynamic values are sorted by the global ID to make handle->entry lookups fast
235  *
236  * Memory allocation
237  * =================
238  * - the memory used by NVTable is managed by the caller, sometimes it is
239  * allocated inside an existing data structure (we preallocate space
240  * with LogMessage)
241  *
242  * - when the structure needs to grow the instance pointer itself needs to
243  * be changed. In order to avoid doing that in all the API calls, a
244  * separate nv_table_realloc() call is provided.
245  *
246  * - NVTable instances are reference counted, but the reference counts are
247  * not thread safe (and accessing NVTable itself isn't either). When
248  * reallocation is needed and multiple references exist, NVTable clones
249  * itself and leaves the old copy be.
250  *
251  * - It is possible to clone an NVTable, which basically copies the
252  * underlying memory contents.
253  *
254  * Limits
255  * ======
256  * There might be various assumptions here and there in the code that fields
257  * in this structure should be limited in values. These are as follows.
258  * (the list is not necessarily comprehensive though, so please be careful
259  * when changing types).
260  * - index_size is used to allocate NVIndexEntry arrays on the stack,
261  * so 2^16 * sizeof(NVIndexEntry) is allocated at most (512k). If you
262  * however change this limit, please be careful to audit the
263  * deserialization code.
264  *
265  */
266 struct _NVTable
267 {
268  /* byte order indication, etc. */
269  guint32 size;
270  guint32 used;
271 
272  /* this used to be called num_dyn_entries in earlier versions, it matches
273  * the type of the original type, so it is compatible with earlier
274  * versions, but index_size is a more descriptive name */
275  guint16 index_size;
277  guint8 ref_cnt: 7,
278  borrowed: 1; /* specifies if the memory used by NVTable was borrowed from the container struct */
279 
280  /* variable data, see memory layout in the comment above */
281  union
282  {
284  guint32 static_entries[0];
285  gchar data[0];
286  };
287 };
288 
289 #define NV_TABLE_BOUND(x) (((x) + 0x3) & ~0x3)
290 #define NV_TABLE_ADDR(self, x) ((gchar *) ((self)) + ((gssize)(x)))
291 
292 /* 256MB, this is an artificial limit, but must be less than MAX_GUINT32 as
293  * we want to compare a guint32 to this variable without overflow. */
294 #define NV_TABLE_MAX_BYTES (256*1024*1024)
295 
296 /* this has to be large enough to hold the NVTable struct above and the
297  * static values */
298 #define NV_TABLE_MIN_BYTES 128
299 
300 gboolean nv_table_add_value(NVTable *self, NVHandle handle,
301  const gchar *name, gsize name_len,
302  const gchar *value, gsize value_len,
303  NVType type, gboolean *new_entry);
304 gboolean nv_table_unset_value(NVTable *self, NVHandle handle);
305 gboolean nv_table_add_value_indirect(NVTable *self, NVHandle handle,
306  const gchar *name, gsize name_len,
307  NVReferencedSlice *referenced_slice,
308  NVType type, gboolean *new_entry);
309 
310 gboolean nv_table_foreach(NVTable *self, NVRegistry *registry, NVTableForeachFunc func, gpointer user_data);
311 gboolean nv_table_foreach_entry(NVTable *self, NVTableForeachEntryFunc func, gpointer user_data);
312 
313 NVTable *nv_table_new(gint num_static_values, gint index_size_hint, gint init_length);
314 NVTable *nv_table_init_borrowed(gpointer space, gsize space_len, gint num_static_entries);
315 gboolean nv_table_realloc(NVTable *self, NVTable **new_nv_table);
316 NVTable *nv_table_compact(NVTable *self);
317 NVTable *nv_table_clone(NVTable *self, gint additional_space);
318 NVTable *nv_table_ref(NVTable *self);
319 void nv_table_unref(NVTable *self);
320 
321 static inline gboolean
322 nv_table_is_handle_static(NVTable *self, NVHandle handle)
323 {
324  return (handle <= self->num_static_entries);
325 }
326 
327 static inline gsize
328 nv_table_get_alloc_size(gint num_static_entries, gint index_size_hint, gint init_length)
329 {
330  NVTable *self G_GNUC_UNUSED = NULL;
331  gsize size;
332 
333  size = NV_TABLE_BOUND(init_length) + NV_TABLE_BOUND(sizeof(NVTable) + num_static_entries * sizeof(
334  self->static_entries[0]) + index_size_hint * sizeof(NVIndexEntry));
335  if (size < NV_TABLE_MIN_BYTES)
336  return NV_TABLE_MIN_BYTES;
337  if (size > NV_TABLE_MAX_BYTES)
338  size = NV_TABLE_MAX_BYTES;
339  return size;
340 }
341 
342 static inline gchar *
343 nv_table_get_top(NVTable *self)
344 {
345  return NV_TABLE_ADDR(self, self->size);
346 }
347 
348 static inline gchar *
349 nv_table_get_bottom(NVTable *self)
350 {
351  return nv_table_get_top(self) - self->used;
352 }
353 
354 static inline gchar *
355 nv_table_get_ofs_table_top(NVTable *self)
356 {
357  return (gchar *) &self->data[self->num_static_entries * sizeof(self->static_entries[0]) +
358  self->index_size * sizeof(NVIndexEntry)];
359 }
360 
361 static inline gboolean
362 nv_table_alloc_check(NVTable *self, gsize alloc_size)
363 {
364  if ((gsize)(nv_table_get_bottom(self) - nv_table_get_ofs_table_top(self)) < alloc_size)
365  return FALSE;
366  return TRUE;
367 }
368 
369 /* private declarations for inline functions */
370 NVEntry *nv_table_get_entry_slow(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry **index_slot);
371 const gchar *nv_table_resolve_indirect(NVTable *self, NVEntry *entry, gssize *len);
372 
373 
374 static inline NVEntry *
375 __nv_table_get_entry(NVTable *self, NVHandle handle, guint16 num_static_entries, NVIndexEntry **index_entry,
376  NVIndexEntry **index_slot)
377 {
378  guint32 ofs;
379  NVIndexEntry *t1, *t2;
380 
381  if (!index_entry)
382  index_entry = &t1;
383  if (!index_slot)
384  index_slot = &t2;
385 
386  if (G_UNLIKELY(!handle))
387  {
388  *index_entry = NULL;
389  *index_slot = NULL;
390  return NULL;
391  }
392 
393  if (G_LIKELY(nv_table_is_handle_static(self, handle)))
394  {
395  ofs = self->static_entries[handle - 1];
396  *index_entry = NULL;
397  *index_slot = NULL;
398  if (G_UNLIKELY(!ofs))
399  return NULL;
400  return (NVEntry *) (nv_table_get_top(self) - ofs);
401  }
402  else
403  {
404  return nv_table_get_entry_slow(self, handle, index_entry, index_slot);
405  }
406 }
407 
408 static inline NVEntry *
409 nv_table_get_entry(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry **index_slot)
410 {
411  return __nv_table_get_entry(self, handle, self->num_static_entries, index_entry, index_slot);
412 }
413 
414 static inline gboolean
415 nv_table_is_value_set(NVTable *self, NVHandle handle)
416 {
417  return nv_table_get_entry(self, handle, NULL, NULL) != NULL;
418 }
419 
420 static inline const gchar *
421 nv_table_get_value(NVTable *self, NVHandle handle, gssize *length, NVType *type)
422 {
423  NVEntry *entry;
424 
425  entry = nv_table_get_entry(self, handle, NULL, NULL);
426  if (!entry || entry->unset)
427  {
428  if (length)
429  *length = 0;
430  return NULL;
431  }
432 
433  if (type)
434  *type = entry->type;
435  if (!entry->indirect)
436  {
437  if (length)
438  *length = entry->vdirect.value_len;
439  return entry->vdirect.data + entry->name_len + 1;
440  }
441  return nv_table_resolve_indirect(self, entry, length);
442 }
443 
444 static inline NVIndexEntry *
445 nv_table_get_index(NVTable *self)
446 {
447  return (NVIndexEntry *)&self->static_entries[self->num_static_entries];
448 }
449 
450 static inline NVEntry *
451 nv_table_get_entry_at_ofs(NVTable *self, guint32 ofs)
452 {
453  if (!ofs)
454  return NULL;
455  return (NVEntry *)(nv_table_get_top(self) - ofs);
456 }
457 
458 static inline guint32
459 nv_table_get_ofs_for_an_entry(NVTable *self, NVEntry *entry)
460 {
461  return (nv_table_get_top(self) - (gchar *) entry);
462 }
463 
464 static inline gssize
465 nv_table_get_memory_consumption(NVTable *self)
466 {
467  return sizeof(*self) +
468  self->num_static_entries * sizeof(self->static_entries[0]) +
469  self->used;
470 }
471 
472 #endif
const gchar * name
Definition: debugger.c:265
#define nvhandle_desc_array_index(self, i)
Definition: nvhandle-descriptors.h:50
NVHandle nv_registry_get_handle(NVRegistry *self, const gchar *name)
Definition: nvtable.c:35
#define NV_TABLE_BOUND(x)
Definition: nvtable.h:289
NVRegistry * nv_registry_new(const gchar **static_names, guint32 nvhandle_max_value)
Definition: nvtable.c:143
NVTable * nv_table_clone(NVTable *self, gint additional_space)
Definition: nvtable.c:812
NVTable * nv_table_new(gint num_static_values, gint index_size_hint, gint init_length)
Definition: nvtable.c:720
void nv_registry_add_alias(NVRegistry *self, NVHandle handle, const gchar *alias)
Definition: nvtable.c:101
void nv_table_unref(NVTable *self)
Definition: nvtable.c:796
const gchar * nv_table_resolve_indirect(NVTable *self, NVEntry *entry, gssize *len)
Definition: nvtable.c:197
void nv_registry_assert_next_handle(NVRegistry *self, NVHandle handle)
Definition: nvtable.c:117
void nv_registry_set_handle_flags(NVRegistry *self, NVHandle handle, guint16 flags)
Definition: nvtable.c:125
gboolean nv_table_foreach_entry(NVTable *self, NVTableForeachEntryFunc func, gpointer user_data)
Definition: nvtable.c:675
guint8 NVType
Definition: nvtable.h:36
gboolean nv_table_foreach(NVTable *self, NVRegistry *registry, NVTableForeachFunc func, gpointer user_data)
Definition: nvtable.c:667
void nv_registry_foreach(NVRegistry *self, GHFunc callback, gpointer user_data)
Definition: nvtable.c:137
gboolean nv_table_add_value(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, const gchar *value, gsize value_len, NVType type, gboolean *new_entry)
Definition: nvtable.c:450
NVHandle nv_registry_alloc_handle(NVRegistry *self, const gchar *name)
Definition: nvtable.c:46
gboolean nv_table_add_value_indirect(NVTable *self, NVHandle handle, const gchar *name, gsize name_len, NVReferencedSlice *referenced_slice, NVType type, gboolean *new_entry)
Definition: nvtable.c:586
#define NV_TABLE_ADDR(self, x)
Definition: nvtable.h:290
void nv_registry_free(NVRegistry *self)
Definition: nvtable.c:159
gboolean(* NVTableForeachFunc)(NVHandle handle, const gchar *name, const gchar *value, gssize value_len, NVType type, gpointer user_data)
Definition: nvtable.h:37
NVTable * nv_table_compact(NVTable *self)
Definition: nvtable.c:898
#define NV_TABLE_MAX_BYTES
Definition: nvtable.h:294
const gchar * null_string
Definition: nvtable.c:32
NVTable * nv_table_ref(NVTable *self)
Definition: nvtable.c:789
gboolean(* NVTableForeachEntryFunc)(NVHandle handle, NVEntry *entry, NVIndexEntry *index_entry, gpointer user_data)
Definition: nvtable.h:40
NVTable * nv_table_init_borrowed(gpointer space, gsize space_len, gint num_static_entries)
Definition: nvtable.c:733
guint32 NVHandle
Definition: nvtable.h:35
gboolean nv_table_realloc(NVTable *self, NVTable **new_nv_table)
Definition: nvtable.c:746
void nv_registry_add_predefined(NVRegistry *self, NVHandle handle, const gchar *name)
Definition: nvtable.c:109
#define NV_TABLE_MIN_BYTES
Definition: nvtable.h:298
NVEntry * nv_table_get_entry_slow(NVTable *self, NVHandle handle, NVIndexEntry **index_entry, NVIndexEntry **index_slot)
Definition: nvtable.c:314
gboolean nv_table_unset_value(NVTable *self, NVHandle handle)
Definition: nvtable.c:507
#define self
Definition: rcptid.c:38
Definition: nvhandle-descriptors.h:38
Definition: nvtable.h:119
guint32 ofs
Definition: nvtable.h:121
NVHandle handle
Definition: nvtable.h:120
guint32 len
Definition: nvtable.h:122
Definition: nvtable.h:129
guint8 type_present
Definition: nvtable.h:150
guint8 unset
Definition: nvtable.h:149
guint8 __bit_padding
Definition: nvtable.h:151
guint8 referenced
Definition: nvtable.h:148
struct _NVEntry::@44::@49 vindirect
guint8 __reserved
Definition: nvtable.h:162
guint32 value_len
Definition: nvtable.h:168
guint8 name_len
Definition: nvtable.h:155
guint32 len
Definition: nvtable.h:177
guint32 alloc_len
Definition: nvtable.h:163
gchar name[0]
Definition: nvtable.h:190
NVHandle handle
Definition: nvtable.h:175
guint8 flags
Definition: nvtable.h:153
struct _NVEntry::@44::@48 vdirect
guint8 indirect
Definition: nvtable.h:147
guint32 ofs
Definition: nvtable.h:176
NVType type
Definition: nvtable.h:156
guint8 __deprecated_type_field
Definition: nvtable.h:188
gchar data[]
Definition: nvtable.h:170
Definition: nvtable.h:55
NVHandle handle
Definition: nvtable.h:56
guint32 ofs
Definition: nvtable.h:57
Definition: nvtable.h:61
NVHandleDescArray * names
Definition: nvtable.h:64
GHashTable * name_map
Definition: nvtable.h:65
guint32 nvhandle_max_value
Definition: nvtable.h:66
gint num_static_names
Definition: nvtable.h:63
Definition: nvtable.h:267
guint16 index_size
Definition: nvtable.h:275
guint32 size
Definition: nvtable.h:269
guint32 static_entries[0]
Definition: nvtable.h:284
guint8 num_static_entries
Definition: nvtable.h:276
guint8 ref_cnt
Definition: nvtable.h:277
guint32 used
Definition: nvtable.h:270
guint32 __dummy_for_alignment
Definition: nvtable.h:283
gchar data[0]
Definition: nvtable.h:285
guint8 borrowed
Definition: nvtable.h:278
GString * value
Definition: test_decode.c:28