summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2010-06-14 16:11:04 +0200
committerAlexander Larsson <alexl@redhat.com>2010-06-18 16:32:11 +0200
commit0cca1ed2af3f74ec6519382c2d52dbfaa9762700 (patch)
treebef026a18f905b74e8158d084e03f5e5ad484423 /common
parent1a0b3fbdbb4d0c0cb54415e361dcd2af164ecdd7 (diff)
downloadspice-0cca1ed2af3f74ec6519382c2d52dbfaa9762700.tar.gz
spice-0cca1ed2af3f74ec6519382c2d52dbfaa9762700.tar.xz
spice-0cca1ed2af3f74ec6519382c2d52dbfaa9762700.zip
Add SpiceMarshaller for easy marshalling
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am2
-rw-r--r--common/marshaller.c588
-rw-r--r--common/marshaller.h58
3 files changed, 648 insertions, 0 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index 222965e8..5c1d6e07 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -39,6 +39,8 @@ COMMON_SRCS = \
lz_config.h \
lz_decompress_tmpl.c \
lz.h \
+ marshaller.h \
+ marshaller.c \
quic_family_tmpl.c \
quic_rgb_tmpl.c \
quic_tmpl.c \
diff --git a/common/marshaller.c b/common/marshaller.c
new file mode 100644
index 00000000..13385e59
--- /dev/null
+++ b/common/marshaller.c
@@ -0,0 +1,588 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2010 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include "marshaller.h"
+#include "mem.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#ifdef WORDS_BIGENDIAN
+#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
+#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
+#define write_int16(ptr,v) (*((int16_t)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
+#define write_uint16(ptr,v) (*((uint16_t)(ptr)) = SPICE_BYTESWAP16((uint16_t)(v)))
+#define write_int32(ptr,v) (*((int32_t)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
+#define write_uint32(ptr,v) (*((uint32_t)(ptr)) = SPICE_BYTESWAP32((uint32_t)(v)))
+#define write_int64(ptr,v) (*((int64_t)(ptr)) = SPICE_BYTESWAP64((uint63_t)(v)))
+#define write_uint64(ptr,v) (*((uint64_t)(ptr)) = SPICE_BYTESWAP64((uint63_t)(v)))
+#else
+#define write_int8(ptr,v) (*((int8_t *)(ptr)) = v)
+#define write_uint8(ptr,v) (*((uint8_t *)(ptr)) = v)
+#define write_int16(ptr,v) (*((int16_t *)(ptr)) = v)
+#define write_uint16(ptr,v) (*((uint16_t *)(ptr)) = v)
+#define write_int32(ptr,v) (*((int32_t *)(ptr)) = v)
+#define write_uint32(ptr,v) (*((uint32_t *)(ptr)) = v)
+#define write_int64(ptr,v) (*((int64_t *)(ptr)) = v)
+#define write_uint64(ptr,v) (*((uint64_t *)(ptr)) = v)
+#endif
+
+typedef struct {
+ uint8_t *data;
+ size_t len;
+ spice_marshaller_item_free_func free_data;
+ void *opaque;
+} MarshallerItem;
+
+/* Try to fit in 4k page with 2*pointer-size overhead (next ptr and malloc size) */
+#define MARSHALLER_BUFFER_SIZE (4096 - sizeof(void *) * 2)
+
+typedef struct MarshallerBuffer MarshallerBuffer;
+struct MarshallerBuffer {
+ MarshallerBuffer *next;
+ uint8_t data[MARSHALLER_BUFFER_SIZE];
+};
+
+#define N_STATIC_ITEMS 4
+
+typedef struct SpiceMarshallerData SpiceMarshallerData;
+
+typedef struct {
+ SpiceMarshaller *marshaller;
+ int item_nr;
+ int is_64bit;
+ size_t offset;
+} MarshallerRef;
+
+struct SpiceMarshaller {
+ size_t total_size;
+ SpiceMarshallerData *data;
+ SpiceMarshaller *next;
+
+ MarshallerRef pointer_ref;
+
+ int n_items;
+ int items_size; /* number of items availible in items */
+ MarshallerItem *items;
+
+ MarshallerItem static_items[N_STATIC_ITEMS];
+};
+
+struct SpiceMarshallerData {
+ size_t total_size;
+ size_t base;
+ SpiceMarshaller *marshallers;
+ SpiceMarshaller *last_marshaller;
+
+ size_t current_buffer_position;
+ MarshallerBuffer *current_buffer;
+ MarshallerItem *current_buffer_item;
+ MarshallerBuffer *buffers;
+
+ SpiceMarshaller static_marshaller;
+ MarshallerBuffer static_buffer;
+};
+
+static void spice_marshaller_init(SpiceMarshaller *m,
+ SpiceMarshallerData *data)
+{
+ m->data = data;
+ m->next = NULL;
+ m->total_size = 0;
+ m->pointer_ref.marshaller = NULL;
+ m->n_items = 0;
+ m->items_size = N_STATIC_ITEMS;
+ m->items = m->static_items;
+}
+
+SpiceMarshaller *spice_marshaller_new(void)
+{
+ SpiceMarshallerData *d;
+ SpiceMarshaller *m;
+
+ d = spice_new(SpiceMarshallerData, 1);
+
+ d->last_marshaller = d->marshallers = &d->static_marshaller;
+ d->total_size = 0;
+ d->base = 0;
+ d->buffers = &d->static_buffer;
+ d->buffers->next = NULL;
+ d->current_buffer = d->buffers;
+ d->current_buffer_position = 0;
+ d->current_buffer_item = NULL;
+
+ m = &d->static_marshaller;
+ spice_marshaller_init(m, d);
+
+ return m;
+}
+
+static void free_item_data(SpiceMarshaller *m)
+{
+ MarshallerItem *item;
+ int i;
+
+ /* Free all user data */
+ for (i = 0; i < m->n_items; i++) {
+ item = &m->items[i];
+ if (item->free_data != NULL) {
+ item->free_data(item->data, item->opaque);
+ }
+ }
+}
+
+static void free_items(SpiceMarshaller *m)
+{
+ if (m->items != m->static_items) {
+ free(m->items);
+ }
+}
+
+void spice_marshaller_reset(SpiceMarshaller *m)
+{
+ SpiceMarshaller *m2;
+ SpiceMarshallerData *d;
+
+ /* Only supported for root marshaller */
+ assert(m->data->marshallers == m);
+
+ for (m2 = m; m2 != NULL; m2 = m2->next) {
+ free_item_data(m2);
+
+ /* Free non-root marshallers */
+ if (m2 != m) {
+ free_items(m2);
+ free(m2);
+ }
+ }
+
+ m->next = NULL;
+ m->n_items = 0;
+ m->total_size = 0;
+
+ d = m->data;
+ d->last_marshaller = d->marshallers;
+ d->total_size = 0;
+ d->base = 0;
+ d->current_buffer_item = NULL;
+ d->current_buffer = d->buffers;
+ d->current_buffer_position = 0;
+}
+
+void spice_marshaller_destroy(SpiceMarshaller *m)
+{
+ MarshallerBuffer *buf, *next;
+ SpiceMarshallerData *d;
+
+ /* Only supported for root marshaller */
+ assert(m->data->marshallers == m);
+
+ spice_marshaller_reset(m);
+
+ free_items(m);
+
+ d = m->data;
+
+ buf = d->buffers->next;
+ while (buf != NULL) {
+ next = buf->next;
+ free(buf);
+ buf = next;
+ }
+
+ free(d);
+}
+
+static MarshallerItem *spice_marshaller_add_item(SpiceMarshaller *m)
+{
+ MarshallerItem *item;
+
+ if (m->n_items == m->items_size) {
+ int items_size = m->items_size * 2;
+
+ if (m->items == m->static_items) {
+ m->items = spice_new(MarshallerItem, items_size);
+ memcpy(m->items, m->static_items, sizeof(MarshallerItem) * m->n_items);
+ } else {
+ m->items = spice_renew(MarshallerItem, m->items, items_size);
+ }
+ m->items_size = items_size;
+ }
+ item = &m->items[m->n_items++];
+ item->free_data = NULL;
+
+ return item;
+}
+
+static size_t remaining_buffer_size(SpiceMarshallerData *d)
+{
+ return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
+}
+
+uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
+{
+ MarshallerItem *item;
+ SpiceMarshallerData *d;
+ uint8_t *res;
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ d = m->data;
+
+ /* Check current item */
+ item = &m->items[m->n_items - 1];
+ if (item == d->current_buffer_item &&
+ remaining_buffer_size(d) >= size) {
+ assert(m->n_items >= 1);
+ /* We can piggy back on existing item+buffer */
+ res = item->data + item->len;
+ item->len += size;
+ d->current_buffer_position += size;
+ d->total_size += size;
+ m->total_size += size;
+ return res;
+ }
+
+ item = spice_marshaller_add_item(m);
+
+ if (remaining_buffer_size(d) >= size) {
+ /* Fits in current buffer */
+ item->data = d->current_buffer->data + d->current_buffer_position;
+ item->len = size;
+ d->current_buffer_position += size;
+ d->current_buffer_item = item;
+ } else if (size > MARSHALLER_BUFFER_SIZE / 2) {
+ /* Large item, allocate by itself */
+ item->data = (uint8_t *)spice_malloc(size);
+ item->len = size;
+ item->free_data = (spice_marshaller_item_free_func)free;
+ item->opaque = NULL;
+ } else {
+ /* Use next buffer */
+ if (d->current_buffer->next == NULL) {
+ d->current_buffer->next = spice_new(MarshallerBuffer, 1);
+ d->current_buffer->next->next = NULL;
+ }
+ d->current_buffer = d->current_buffer->next;
+ d->current_buffer_position = size;
+ d->current_buffer_item = item;
+ item->data = d->current_buffer->data;
+ item->len = size;
+ }
+
+ d->total_size += size;
+ m->total_size += size;
+ return item->data;
+}
+
+void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
+{
+ MarshallerItem *item;
+
+ if (size == 0) {
+ return;
+ }
+
+ item = &m->items[m->n_items - 1];
+
+ assert(item->len >= size);
+ item->len -= size;
+}
+
+uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
+ spice_marshaller_item_free_func free_data, void *opaque)
+{
+ MarshallerItem *item;
+ SpiceMarshallerData *d;
+
+ if (data == NULL || size == 0) {
+ return NULL;
+ }
+
+ item = spice_marshaller_add_item(m);
+ item->data = data;
+ item->len = size;
+ item->free_data = free_data;
+ item->opaque = opaque;
+
+ d = m->data;
+ m->total_size += size;
+ d->total_size += size;
+
+ return data;
+}
+
+uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, size);
+ memcpy(ptr, data, size);
+ return ptr;
+}
+
+uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size)
+{
+ return spice_marshaller_add_ref_full(m, data, size, NULL, NULL);
+}
+
+SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
+{
+ SpiceMarshallerData *d;
+ SpiceMarshaller *m2;
+
+ d = m->data;
+
+ m2 = spice_new(SpiceMarshaller, 1);
+ spice_marshaller_init(m2, d);
+
+ d->last_marshaller->next = m2;
+ d->last_marshaller = m2;
+
+ return m2;
+}
+
+SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit)
+{
+ SpiceMarshaller *m2;
+ uint8_t *p;
+ int size;
+
+ size = is_64bit ? 8 : 4;
+
+ p = spice_marshaller_reserve_space(m, size);
+ memset(p, 0, size);
+ m2 = spice_marshaller_get_submarshaller(m);
+ m2->pointer_ref.marshaller = m;
+ m2->pointer_ref.item_nr = m->n_items - 1;
+ m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
+ m2->pointer_ref.is_64bit = is_64bit;
+
+ return m2;
+}
+
+uint8_t *lookup_ref(MarshallerRef *ref)
+{
+ MarshallerItem *item;
+
+ item = &ref->marshaller->items[ref->item_nr];
+ return item->data + ref->offset;
+}
+
+
+void spice_marshaller_set_base(SpiceMarshaller *m, size_t base)
+{
+ /* Only supported for root marshaller */
+ assert(m->data->marshallers == m);
+
+ m->data->base = base;
+}
+
+uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
+ size_t *len, int *free_res)
+{
+ MarshallerItem *item;
+ uint8_t *res, *p;
+ int i;
+
+ /* Only supported for root marshaller */
+ assert(m->data->marshallers == m);
+
+ if (m->n_items == 1) {
+ *free_res = FALSE;
+ if (m->items[0].len <= skip_bytes) {
+ *len = 0;
+ return NULL;
+ }
+ *len = m->items[0].len - skip_bytes;
+ return m->items[0].data + skip_bytes;
+ }
+
+ *free_res = TRUE;
+ res = (uint8_t *)spice_malloc(m->data->total_size - skip_bytes);
+ *len = m->data->total_size - skip_bytes;
+ p = res;
+
+ do {
+ for (i = 0; i < m->n_items; i++) {
+ item = &m->items[i];
+
+ if (item->len <= skip_bytes) {
+ skip_bytes -= item->len;
+ continue;
+ }
+ memcpy(p, item->data + skip_bytes, item->len - skip_bytes);
+ p += item->len - skip_bytes;
+ skip_bytes = 0;
+ }
+ m = m->next;
+ } while (m != NULL);
+
+ return res;
+}
+
+uint8_t *spice_marshaller_get_ptr(SpiceMarshaller *m)
+{
+ return m->items[0].data;
+}
+
+size_t spice_marshaller_get_offset(SpiceMarshaller *m)
+{
+ SpiceMarshaller *m2;
+ size_t offset;
+
+ offset = 0;
+ m2 = m->data->marshallers;
+ while (m2 != m) {
+ offset += m2->total_size;
+ m2 = m2->next;
+ }
+ return offset - m->data->base;
+}
+
+size_t spice_marshaller_get_size(SpiceMarshaller *m)
+{
+ return m->total_size;
+}
+
+size_t spice_marshaller_get_total_size(SpiceMarshaller *m)
+{
+ return m->data->total_size;
+}
+
+void spice_marshaller_flush(SpiceMarshaller *m)
+{
+ SpiceMarshaller *m2;
+ uint8_t *ptr_pos;
+
+ /* Only supported for root marshaller */
+ assert(m->data->marshallers == m);
+
+ for (m2 = m; m2 != NULL; m2 = m2->next) {
+ if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
+ ptr_pos = lookup_ref(&m2->pointer_ref);
+ if (m2->pointer_ref.is_64bit) {
+ write_uint64(ptr_pos,
+ spice_marshaller_get_offset(m2));
+ } else {
+ write_uint32(ptr_pos,
+ spice_marshaller_get_offset(m2));
+ }
+ }
+ }
+}
+
+int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
+ int n_vec, size_t skip_bytes)
+{
+ MarshallerItem *item;
+ int v, i;
+
+ /* Only supported for root marshaller */
+ assert(m->data->marshallers == m);
+
+ v = 0;
+ do {
+ for (i = 0; i < m->n_items; i++) {
+ item = &m->items[i];
+
+ if (item->len <= skip_bytes) {
+ skip_bytes -= item->len;
+ continue;
+ }
+ if (v == n_vec) {
+ return v; /* Not enough space in vec */
+ }
+ vec[v].iov_base = item->data + skip_bytes;
+ vec[v].iov_len = item->len - skip_bytes;
+ skip_bytes = 0;
+ v++;
+ }
+ m = m->next;
+ } while (m != NULL);
+
+ return v;
+}
+
+void spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(uint64_t));
+ write_uint64(ptr, v);
+}
+
+void spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(int64_t));
+ write_int64(ptr, v);
+}
+
+void spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(uint32_t));
+ write_uint32(ptr, v);
+}
+
+void spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(int32_t));
+ write_int32(ptr, v);
+}
+
+void spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(uint16_t));
+ write_uint16(ptr, v);
+}
+
+void spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(int16_t));
+ write_int16(ptr, v);
+}
+
+void spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(uint8_t));
+ write_uint8(ptr, v);
+}
+
+void spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
+{
+ uint8_t *ptr;
+
+ ptr = spice_marshaller_reserve_space(m, sizeof(int8_t));
+ write_int8(ptr, v);
+}
diff --git a/common/marshaller.h b/common/marshaller.h
new file mode 100644
index 00000000..3b159aa9
--- /dev/null
+++ b/common/marshaller.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2010 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_MARSHALLER
+#define _H_MARSHALLER
+
+#include <spice/types.h>
+#include <sys/uio.h>
+
+typedef struct SpiceMarshaller SpiceMarshaller;
+typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
+
+SpiceMarshaller *spice_marshaller_new(void);
+void spice_marshaller_reset(SpiceMarshaller *m);
+void spice_marshaller_destroy(SpiceMarshaller *m);
+uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size);
+void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size);
+uint8_t *spice_marshaller_add(SpiceMarshaller *m, uint8_t *data, size_t size);
+uint8_t *spice_marshaller_add_ref(SpiceMarshaller *m, uint8_t *data, size_t size);
+uint8_t *spice_marshaller_add_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
+ spice_marshaller_item_free_func free_data, void *opaque);
+void spice_marshaller_flush(SpiceMarshaller *m);
+void spice_marshaller_set_base(SpiceMarshaller *m, size_t base);
+uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip,
+ size_t *len, int *free_res);
+uint8_t *spice_marshaller_get_ptr(SpiceMarshaller *m);
+size_t spice_marshaller_get_offset(SpiceMarshaller *m);
+size_t spice_marshaller_get_size(SpiceMarshaller *m);
+size_t spice_marshaller_get_total_size(SpiceMarshaller *m);
+SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m);
+SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m, int is_64bit);
+int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
+ int n_vec, size_t skip_bytes);
+void spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v);
+void spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v);
+void spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v);
+void spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v);
+void spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v);
+void spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v);
+void spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v);
+void spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
+
+#endif