]> git.ipfire.org Git - thirdparty/lldpd.git/blob - src/marshal.h
e28a011df876acdcf8e1db6f693105dd10215576
[thirdparty/lldpd.git] / src / marshal.h
1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #ifndef _MARSHAL_H
19 #define _MARSHAL_H
20
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <sys/types.h>
24
25 struct marshal_info;
26 enum marshal_subinfo_kind {
27 pointer,
28 substruct,
29 ignore,
30 };
31 #define MARSHAL_INFO_POINTER 1
32 #define MARSHAL_INFO_SUB 2
33 struct marshal_subinfo {
34 size_t offset; /* Offset compared to parent structure */
35 size_t offset2; /* Ancillary offset (for related data) */
36 enum marshal_subinfo_kind kind; /* Kind of substructure */
37 struct marshal_info *mi;
38 };
39 #define MARSHAL_SUBINFO_NULL \
40 { \
41 .offset = 0, .offset2 = 0, .kind = ignore, .mi = NULL \
42 }
43 struct marshal_info {
44 const char *name; /* Name of structure */
45 size_t size; /* Size of the structure */
46 #if defined __GNUC__ && __GNUC__ < 3
47 /* With gcc 2.96, flexible arrays are not supported, even with
48 * -std=gnu99. And with gcc 3.x, zero-sized arrays cannot be statically
49 * initialized (with more than one element). */
50 struct marshal_subinfo pointers[0]; /* Pointer to other structures */
51 #else
52 struct marshal_subinfo pointers[]; /* Pointer to other structures */
53 #endif
54 };
55 /* Special case for strings */
56 extern struct marshal_info marshal_info_string;
57 extern struct marshal_info marshal_info_fstring;
58 extern struct marshal_info marshal_info_ignore;
59
60 /* Declare a new marshal_info struct named after the type we want to
61 marshal. The marshalled type has to be a structure. */
62 #define MARSHAL_INFO(type) marshal_info_##type
63 #ifdef MARSHAL_EXPORT
64 # define MARSHAL_HELPER_FUNCTIONS(type, ttype) \
65 ssize_t type##_serialize(ttype *source, void *buffer); \
66 ssize_t type##_serialize(ttype *source, void *buffer) \
67 { \
68 return marshal_serialize(type, source, buffer); \
69 } \
70 size_t type##_unserialize(void *buffer, size_t len, ttype **destination); \
71 size_t type##_unserialize(void *buffer, size_t len, ttype **destination) \
72 { \
73 void *p; \
74 size_t rc; \
75 rc = marshal_unserialize(type, buffer, len, &p); \
76 if (rc <= 0) return rc; \
77 *destination = p; \
78 return rc; \
79 }
80 # define MARSHAL_BEGIN(type) \
81 struct marshal_info MARSHAL_INFO( \
82 type) = { .name = #type, .size = sizeof(struct type), .pointers = {
83 # define MARSHAL_ADD(_kind, type, subtype, member) \
84 { .offset = offsetof(struct type, member), \
85 .offset2 = 0, \
86 .kind = _kind, \
87 .mi = &MARSHAL_INFO(subtype) },
88 # define MARSHAL_FSTR(type, member, len) \
89 { .offset = offsetof(struct type, member), \
90 .offset2 = offsetof(struct type, len), \
91 .kind = pointer, \
92 .mi = &marshal_info_fstring },
93 # define MARSHAL_END(type) \
94 MARSHAL_SUBINFO_NULL \
95 } \
96 } \
97 ; \
98 MARSHAL_HELPER_FUNCTIONS(type, struct type)
99 #else
100 # define MARSHAL_HELPER_FUNCTIONS(type, ttype) \
101 ssize_t type##_serialize(ttype *, void *); \
102 size_t type##_unserialize(void *, size_t, ttype **);
103 # define MARSHAL_BEGIN(type) extern struct marshal_info MARSHAL_INFO(type);
104 # define MARSHAL_ADD(...)
105 # define MARSHAL_FSTR(...)
106 # define MARSHAL_END(type) MARSHAL_HELPER_FUNCTIONS(type, struct type)
107 #endif
108 /* Shortcuts */
109 #define MARSHAL_POINTER(...) MARSHAL_ADD(pointer, ##__VA_ARGS__)
110 #define MARSHAL_SUBSTRUCT(...) MARSHAL_ADD(substruct, ##__VA_ARGS__)
111 #define MARSHAL_STR(type, member) MARSHAL_ADD(pointer, type, string, member)
112 #define MARSHAL_IGNORE(type, member) MARSHAL_ADD(ignore, type, ignore, member)
113 #define MARSHAL_TQE(type, field) \
114 MARSHAL_POINTER(type, type, field.tqe_next) \
115 MARSHAL_IGNORE(type, field.tqe_prev)
116 /* Support for TAILQ list is partial. Access to last and previous
117 elements is not available. Some operations are therefore not
118 possible. However, TAILQ_FOREACH is still
119 available. */
120 #define MARSHAL_TQH(type, subtype) \
121 MARSHAL_POINTER(type, subtype, tqh_first) \
122 MARSHAL_IGNORE(type, tqh_last)
123 #define MARSHAL_SUBTQ(type, subtype, field) \
124 MARSHAL_POINTER(type, subtype, field.tqh_first) \
125 MARSHAL_IGNORE(type, field.tqh_last)
126 #define MARSHAL(type) \
127 MARSHAL_BEGIN(type) \
128 MARSHAL_END(type)
129 #define MARSHAL_TQ(type, subtype) \
130 MARSHAL_BEGIN(type) \
131 MARSHAL_TQH(type, subtype) \
132 MARSHAL_END(type)
133
134 /* Serialization */
135 ssize_t marshal_serialize_(struct marshal_info *, void *, void **, int, void *, int)
136 __attribute__((nonnull(1, 2, 3)));
137 #define marshal_serialize(type, o, output) \
138 marshal_serialize_(&MARSHAL_INFO(type), o, output, 0, NULL, 0)
139
140 /* Unserialization */
141 size_t marshal_unserialize_(struct marshal_info *, void *, size_t, void **, void *, int,
142 int) __attribute__((nonnull(1, 2, 4)));
143 #define marshal_unserialize(type, o, l, input) \
144 marshal_unserialize_(&MARSHAL_INFO(type), o, l, input, NULL, 0, 0)
145
146 #define marshal_repair_tailq(type, head, field) \
147 do { \
148 struct type *__item, *__item_next; \
149 (head)->tqh_last = &(head)->tqh_first; \
150 for (__item = TAILQ_FIRST(head); __item != NULL; __item = __item_next) { \
151 __item_next = TAILQ_NEXT(__item, field); \
152 __item->field.tqe_prev = (head)->tqh_last; \
153 *(head)->tqh_last = __item; \
154 (head)->tqh_last = &__item->field.tqe_next; \
155 } \
156 } while (0)
157
158 #endif