diff options
-rw-r--r-- | src/libmdsclient/inbound.c | 42 | ||||
-rw-r--r-- | src/libmdsclient/inbound.h | 22 |
2 files changed, 62 insertions, 2 deletions
diff --git a/src/libmdsclient/inbound.c b/src/libmdsclient/inbound.c index 739cbcb..7b8a0fc 100644 --- a/src/libmdsclient/inbound.c +++ b/src/libmdsclient/inbound.c @@ -52,6 +52,7 @@ int libmds_message_initialise(libmds_message_t* restrict this) this->buffer_ptr = 0; this->stage = 0; this->buffer = malloc(this->buffer_size * sizeof(char)); + this->flattened = 0; return this->buffer == NULL ? -1 : 0; } @@ -64,8 +65,45 @@ int libmds_message_initialise(libmds_message_t* restrict this) */ void libmds_message_destroy(libmds_message_t* restrict this) { - free(this->headers), this->headers = NULL; - free(this->buffer), this->buffer = NULL; + if (this->flattened == 0) + { + free(this->headers), this->headers = NULL; + free(this->buffer), this->buffer = NULL; + } +} + + +/** + * Release all resources in a message, should + * be done even if initialisation fails + * + * @param this The message + * @return The duplicate, you do not need to call `libmds_message_destroy` + * on it before you call `free` on it. However, you cannot use + * this is an `libmds_message_t` array (libmds_message_t*), only + * in an `libmds_message_t*` array (libmds_message_t**). + */ +libmds_message_t* libmds_message_duplicate(libmds_message_t* restrict this) +{ + size_t flattened_size, i, n = this->header_count; + libmds_message_t* rc; + + flattened_size = sizeof(libmds_message_t) + this->buffer_off * sizeof(char) + n * sizeof(void*); + if (rc = malloc(flattened_size), rc == NULL) + return NULL; + + *rc = *this; + rc->flattened = flattened_size; + rc->buffer_size = this->buffer_off; + + rc->buffer = ((char*)rc) + sizeof(libmds_message_t) / sizeof(char); + rc->headers = (char**)(void*)(rc->buffer + this->buffer_off); + rc->payload = rc->buffer + (size_t)(this->payload - this->buffer); + for (i = 0; i < n; i++) + rc->headers[i] = rc->buffer + (size_t)(this->headers[i] - this->buffer); + + memcpy(rc->buffer, this->buffer, this->buffer_off * sizeof(char)); + return rc; } diff --git a/src/libmdsclient/inbound.h b/src/libmdsclient/inbound.h index f0e3d20..87b96f4 100644 --- a/src/libmdsclient/inbound.h +++ b/src/libmdsclient/inbound.h @@ -76,6 +76,15 @@ typedef struct libmds_message size_t buffer_off; /** + * Zero unless the structure is flattend, otherwise + * the size of the object (semiinternal data) + * + * Flattened means that all pointers are subpointers + * of the object itself + */ + size_t flattened; + + /** * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) */ int stage; @@ -108,6 +117,19 @@ __attribute__((nonnull)) void libmds_message_destroy(libmds_message_t* restrict this); /** + * Release all resources in a message, should + * be done even if initialisation fails + * + * @param this The message + * @return The duplicate, you do not need to call `libmds_message_destroy` + * on it before you call `free` on it. However, you cannot use + * this is an `libmds_message_t` array (libmds_message_t*), only + * in an `libmds_message_t*` array (libmds_message_t**). + */ +__attribute__((nonnull, malloc, warn_unused_result)) +libmds_message_t* libmds_message_duplicate(libmds_message_t* restrict this); + +/** * Read the next message from a file descriptor * * @param this Memory slot in which to store the new message |