/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2012 Vincent Bernat * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _MARSHAL_H #define _MARSHAL_H #include #include #include struct marshal_info; enum marshal_subinfo_kind { pointer, substruct, ignore, }; #define MARSHAL_INFO_POINTER 1 #define MARSHAL_INFO_SUB 2 struct marshal_subinfo { size_t offset; /* Offset compared to parent structure */ size_t offset2; /* Ancillary offset (for related data) */ enum marshal_subinfo_kind kind; /* Kind of substructure */ struct marshal_info *mi; }; #define MARSHAL_SUBINFO_NULL \ { \ .offset = 0, .offset2 = 0, .kind = ignore, .mi = NULL \ } struct marshal_info { const char *name; /* Name of structure */ size_t size; /* Size of the structure */ #if defined __GNUC__ && __GNUC__ < 3 /* With gcc 2.96, flexible arrays are not supported, even with * -std=gnu99. And with gcc 3.x, zero-sized arrays cannot be statically * initialized (with more than one element). */ struct marshal_subinfo pointers[0]; /* Pointer to other structures */ #else struct marshal_subinfo pointers[]; /* Pointer to other structures */ #endif }; /* Special case for strings */ extern struct marshal_info marshal_info_string; extern struct marshal_info marshal_info_fstring; extern struct marshal_info marshal_info_ignore; /* Declare a new marshal_info struct named after the type we want to marshal. The marshalled type has to be a structure. */ #define MARSHAL_INFO(type) marshal_info_##type #ifdef MARSHAL_EXPORT # define MARSHAL_HELPER_FUNCTIONS(type, ttype) \ ssize_t type##_serialize(ttype *source, void *buffer); \ ssize_t type##_serialize(ttype *source, void *buffer) \ { \ return marshal_serialize(type, source, buffer); \ } \ size_t type##_unserialize(void *buffer, size_t len, ttype **destination); \ size_t type##_unserialize(void *buffer, size_t len, ttype **destination) \ { \ void *p; \ size_t rc; \ rc = marshal_unserialize(type, buffer, len, &p); \ if (rc <= 0) return rc; \ *destination = p; \ return rc; \ } # define MARSHAL_BEGIN(type) \ struct marshal_info MARSHAL_INFO( \ type) = { .name = #type, .size = sizeof(struct type), .pointers = { # define MARSHAL_ADD(_kind, type, subtype, member) \ { .offset = offsetof(struct type, member), \ .offset2 = 0, \ .kind = _kind, \ .mi = &MARSHAL_INFO(subtype) }, # define MARSHAL_FSTR(type, member, len) \ { .offset = offsetof(struct type, member), \ .offset2 = offsetof(struct type, len), \ .kind = pointer, \ .mi = &marshal_info_fstring }, # define MARSHAL_END(type) \ MARSHAL_SUBINFO_NULL \ } \ } \ ; \ MARSHAL_HELPER_FUNCTIONS(type, struct type) #else # define MARSHAL_HELPER_FUNCTIONS(type, ttype) \ ssize_t type##_serialize(ttype *, void *); \ size_t type##_unserialize(void *, size_t, ttype **); # define MARSHAL_BEGIN(type) extern struct marshal_info MARSHAL_INFO(type); # define MARSHAL_ADD(...) # define MARSHAL_FSTR(...) # define MARSHAL_END(type) MARSHAL_HELPER_FUNCTIONS(type, struct type) #endif /* Shortcuts */ #define MARSHAL_POINTER(...) MARSHAL_ADD(pointer, ##__VA_ARGS__) #define MARSHAL_SUBSTRUCT(...) MARSHAL_ADD(substruct, ##__VA_ARGS__) #define MARSHAL_STR(type, member) MARSHAL_ADD(pointer, type, string, member) #define MARSHAL_IGNORE(type, member) MARSHAL_ADD(ignore, type, ignore, member) #define MARSHAL_TQE(type, field) \ MARSHAL_POINTER(type, type, field.tqe_next) \ MARSHAL_IGNORE(type, field.tqe_prev) /* Support for TAILQ list is partial. Access to last and previous elements is not available. Some operations are therefore not possible. However, TAILQ_FOREACH is still available. */ #define MARSHAL_TQH(type, subtype) \ MARSHAL_POINTER(type, subtype, tqh_first) \ MARSHAL_IGNORE(type, tqh_last) #define MARSHAL_SUBTQ(type, subtype, field) \ MARSHAL_POINTER(type, subtype, field.tqh_first) \ MARSHAL_IGNORE(type, field.tqh_last) #define MARSHAL(type) \ MARSHAL_BEGIN(type) \ MARSHAL_END(type) #define MARSHAL_TQ(type, subtype) \ MARSHAL_BEGIN(type) \ MARSHAL_TQH(type, subtype) \ MARSHAL_END(type) /* Serialization */ ssize_t marshal_serialize_(struct marshal_info *, void *, void **, int, void *, int) __attribute__((nonnull(1, 2, 3))); #define marshal_serialize(type, o, output) \ marshal_serialize_(&MARSHAL_INFO(type), o, output, 0, NULL, 0) /* Unserialization */ size_t marshal_unserialize_(struct marshal_info *, void *, size_t, void **, void *, int, int) __attribute__((nonnull(1, 2, 4))); #define marshal_unserialize(type, o, l, input) \ marshal_unserialize_(&MARSHAL_INFO(type), o, l, input, NULL, 0, 0) #define marshal_repair_tailq(type, head, field) \ do { \ struct type *__item, *__item_next; \ (head)->tqh_last = &(head)->tqh_first; \ for (__item = TAILQ_FIRST(head); __item != NULL; __item = __item_next) { \ __item_next = TAILQ_NEXT(__item, field); \ __item->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = __item; \ (head)->tqh_last = &__item->field.tqe_next; \ } \ } while (0) #endif