Line data Source code
1 : /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 : /*
3 : Copyright (C) 2010 Red Hat, Inc.
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, see <http://www.gnu.org/licenses/>.
17 : */
18 : #include <config.h>
19 :
20 : #include "log.h"
21 : #include "marshaller.h"
22 : #include "mem.h"
23 : #include <string.h>
24 : #include <stdlib.h>
25 : #include <assert.h>
26 : #include <unistd.h>
27 : #include <stdio.h>
28 :
29 : #include <spice/start-packed.h>
30 : typedef struct SPICE_ATTR_PACKED {
31 : int16_t val;
32 : } int16_unaligned_t;
33 :
34 : typedef struct SPICE_ATTR_PACKED {
35 : uint16_t val;
36 : } uint16_unaligned_t;
37 :
38 : typedef struct SPICE_ATTR_PACKED {
39 : int32_t val;
40 : } int32_unaligned_t;
41 :
42 : typedef struct SPICE_ATTR_PACKED {
43 : uint32_t val;
44 : } uint32_unaligned_t;
45 :
46 : typedef struct SPICE_ATTR_PACKED {
47 : int64_t val;
48 : } int64_unaligned_t;
49 :
50 : typedef struct SPICE_ATTR_PACKED {
51 : uint64_t val;
52 : } uint64_unaligned_t;
53 : #include <spice/end-packed.h>
54 :
55 : #define write_int8(ptr,v) (*(int8_t *)(ptr) = v)
56 : #define write_uint8(ptr,v) (*(uint8_t *)(ptr) = v)
57 :
58 : #ifdef WORDS_BIGENDIAN
59 : #define write_int16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
60 : #define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = SPICE_BYTESWAP16((uint16_t)(v)))
61 : #define write_int32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
62 : #define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = SPICE_BYTESWAP32((uint32_t)(v)))
63 : #define write_int64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
64 : #define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = SPICE_BYTESWAP64((uint64_t)(v)))
65 : #else
66 : #define write_int16(ptr,v) (((int16_unaligned_t *)(ptr))->val = v)
67 : #define write_uint16(ptr,v) (((uint16_unaligned_t *)(ptr))->val = v)
68 : #define write_int32(ptr,v) (((int32_unaligned_t *)(ptr))->val = v)
69 : #define write_uint32(ptr,v) (((uint32_unaligned_t *)(ptr))->val = v)
70 : #define write_int64(ptr,v) (((int64_unaligned_t *)(ptr))->val = v)
71 : #define write_uint64(ptr,v) (((uint64_unaligned_t *)(ptr))->val = v)
72 : #endif
73 :
74 : typedef struct {
75 : uint8_t *data;
76 : size_t len;
77 : spice_marshaller_item_free_func free_data;
78 : void *opaque;
79 : } MarshallerItem;
80 :
81 : /* Try to fit in 4k page with 2*pointer-size overhead (next ptr and malloc size) */
82 : #define MARSHALLER_BUFFER_SIZE (4096 - sizeof(void *) * 2)
83 :
84 : typedef struct MarshallerBuffer MarshallerBuffer;
85 : struct MarshallerBuffer {
86 : MarshallerBuffer *next;
87 : uint8_t data[MARSHALLER_BUFFER_SIZE];
88 : };
89 :
90 : #define N_STATIC_ITEMS 4
91 :
92 : typedef struct SpiceMarshallerData SpiceMarshallerData;
93 :
94 : typedef struct {
95 : SpiceMarshaller *marshaller;
96 : int item_nr;
97 : size_t offset;
98 : } MarshallerRef;
99 :
100 : struct SpiceMarshaller {
101 : size_t total_size;
102 : SpiceMarshallerData *data;
103 : SpiceMarshaller *next;
104 :
105 : MarshallerRef pointer_ref;
106 :
107 : int n_items;
108 : int items_size; /* number of items available in items */
109 : MarshallerItem *items;
110 :
111 : MarshallerItem static_items[N_STATIC_ITEMS];
112 : bool has_fd;
113 : int fd;
114 : };
115 :
116 : struct SpiceMarshallerData {
117 : size_t total_size;
118 : size_t base;
119 : SpiceMarshaller *last_marshaller;
120 :
121 : size_t current_buffer_position;
122 : MarshallerBuffer *current_buffer;
123 : MarshallerItem *current_buffer_item;
124 :
125 : // first marshaller and buffer are statically allocated here
126 : SpiceMarshaller marshallers[1];
127 : MarshallerBuffer buffers[1];
128 : };
129 :
130 2 : static void spice_marshaller_init(SpiceMarshaller *m,
131 : SpiceMarshallerData *data)
132 : {
133 2 : m->data = data;
134 2 : m->next = NULL;
135 2 : m->total_size = 0;
136 2 : m->pointer_ref.marshaller = NULL;
137 2 : m->n_items = 0;
138 2 : m->items_size = N_STATIC_ITEMS;
139 2 : m->items = m->static_items;
140 2 : m->fd = -1;
141 2 : m->has_fd = false;
142 2 : }
143 :
144 1 : SpiceMarshaller *spice_marshaller_new(void)
145 : {
146 : SpiceMarshallerData *d;
147 : SpiceMarshaller *m;
148 :
149 1 : d = spice_new(SpiceMarshallerData, 1);
150 :
151 1 : d->last_marshaller = d->marshallers;
152 1 : d->total_size = 0;
153 1 : d->base = 0;
154 1 : d->buffers->next = NULL;
155 1 : d->current_buffer = d->buffers;
156 1 : d->current_buffer_position = 0;
157 1 : d->current_buffer_item = NULL;
158 :
159 1 : m = d->marshallers;
160 1 : spice_marshaller_init(m, d);
161 :
162 1 : return m;
163 : }
164 :
165 3 : static void free_item_data(SpiceMarshaller *m)
166 : {
167 : MarshallerItem *item;
168 : int i;
169 :
170 : /* Free all user data */
171 6 : for (i = 0; i < m->n_items; i++) {
172 3 : item = &m->items[i];
173 3 : if (item->free_data != NULL) {
174 0 : item->free_data(item->data, item->opaque);
175 : }
176 : }
177 3 : }
178 :
179 2 : static void free_items(SpiceMarshaller *m)
180 : {
181 2 : if (m->items != m->static_items) {
182 0 : free(m->items);
183 : }
184 2 : }
185 :
186 2 : void spice_marshaller_reset(SpiceMarshaller *m)
187 : {
188 : SpiceMarshaller *m2, *next;
189 : SpiceMarshallerData *d;
190 :
191 : /* Only supported for root marshaller */
192 2 : assert(m->data->marshallers == m);
193 :
194 5 : for (m2 = m; m2 != NULL; m2 = next) {
195 3 : next = m2->next;
196 3 : free_item_data(m2);
197 :
198 : /* Free non-root marshallers */
199 3 : if (m2 != m) {
200 1 : free_items(m2);
201 1 : free(m2);
202 : }
203 : }
204 :
205 2 : m->next = NULL;
206 2 : m->n_items = 0;
207 2 : m->total_size = 0;
208 2 : if (m->has_fd) {
209 0 : m->has_fd = false;
210 0 : if (m->fd != -1) {
211 0 : close(m->fd);
212 : }
213 : }
214 :
215 2 : d = m->data;
216 2 : d->last_marshaller = d->marshallers;
217 2 : d->total_size = 0;
218 2 : d->base = 0;
219 2 : d->current_buffer_item = NULL;
220 2 : d->current_buffer = d->buffers;
221 2 : d->current_buffer_position = 0;
222 2 : }
223 :
224 1 : void spice_marshaller_destroy(SpiceMarshaller *m)
225 : {
226 : MarshallerBuffer *buf, *next;
227 : SpiceMarshallerData *d;
228 :
229 : /* Only supported for root marshaller */
230 1 : assert(m->data->marshallers == m);
231 :
232 1 : spice_marshaller_reset(m);
233 :
234 1 : free_items(m);
235 :
236 1 : d = m->data;
237 :
238 1 : buf = d->buffers->next;
239 1 : while (buf != NULL) {
240 0 : next = buf->next;
241 0 : free(buf);
242 0 : buf = next;
243 : }
244 :
245 1 : free(d);
246 1 : }
247 :
248 3 : static MarshallerItem *spice_marshaller_add_item(SpiceMarshaller *m)
249 : {
250 : MarshallerItem *item;
251 :
252 3 : if (m->n_items == m->items_size) {
253 0 : int items_size = m->items_size * 2;
254 :
255 0 : if (m->items == m->static_items) {
256 0 : m->items = spice_new(MarshallerItem, items_size);
257 0 : memcpy(m->items, m->static_items, sizeof(MarshallerItem) * m->n_items);
258 : } else {
259 0 : m->items = spice_renew(MarshallerItem, m->items, items_size);
260 : }
261 0 : m->items_size = items_size;
262 : }
263 3 : item = &m->items[m->n_items++];
264 3 : item->free_data = NULL;
265 :
266 3 : return item;
267 : }
268 :
269 12 : static size_t remaining_buffer_size(SpiceMarshallerData *d)
270 : {
271 12 : return MARSHALLER_BUFFER_SIZE - d->current_buffer_position;
272 : }
273 :
274 0 : static void reserve_space_free_data(uint8_t *data, SPICE_GNUC_UNUSED void *opaque)
275 : {
276 0 : free(data);
277 0 : }
278 :
279 12 : uint8_t *spice_marshaller_reserve_space(SpiceMarshaller *m, size_t size)
280 : {
281 : MarshallerItem *item;
282 : SpiceMarshallerData *d;
283 : uint8_t *res;
284 :
285 12 : if (size == 0) {
286 0 : return NULL;
287 : }
288 :
289 12 : d = m->data;
290 :
291 : /* Check current item */
292 12 : item = &m->items[m->n_items - 1];
293 21 : if (item == d->current_buffer_item &&
294 9 : remaining_buffer_size(d) >= size) {
295 9 : assert(m->n_items >= 1);
296 : /* We can piggy back on existing item+buffer */
297 9 : res = item->data + item->len;
298 9 : item->len += size;
299 9 : d->current_buffer_position += size;
300 9 : d->total_size += size;
301 9 : m->total_size += size;
302 9 : return res;
303 : }
304 :
305 3 : item = spice_marshaller_add_item(m);
306 :
307 3 : if (remaining_buffer_size(d) >= size) {
308 : /* Fits in current buffer */
309 3 : item->data = d->current_buffer->data + d->current_buffer_position;
310 3 : item->len = size;
311 3 : d->current_buffer_position += size;
312 3 : d->current_buffer_item = item;
313 0 : } else if (size > MARSHALLER_BUFFER_SIZE / 2) {
314 : /* Large item, allocate by itself */
315 0 : item->data = (uint8_t *)spice_malloc(size);
316 0 : item->len = size;
317 0 : item->free_data = reserve_space_free_data;
318 0 : item->opaque = NULL;
319 : } else {
320 : /* Use next buffer */
321 0 : if (d->current_buffer->next == NULL) {
322 0 : d->current_buffer->next = spice_new(MarshallerBuffer, 1);
323 0 : d->current_buffer->next->next = NULL;
324 : }
325 0 : d->current_buffer = d->current_buffer->next;
326 0 : d->current_buffer_position = size;
327 0 : d->current_buffer_item = item;
328 0 : item->data = d->current_buffer->data;
329 0 : item->len = size;
330 : }
331 :
332 3 : d->total_size += size;
333 3 : m->total_size += size;
334 3 : return item->data;
335 : }
336 :
337 0 : void spice_marshaller_unreserve_space(SpiceMarshaller *m, size_t size)
338 : {
339 : MarshallerItem *item;
340 :
341 0 : if (size == 0) {
342 0 : return;
343 : }
344 :
345 0 : item = &m->items[m->n_items - 1];
346 :
347 0 : assert(item->len >= size);
348 0 : item->len -= size;
349 : }
350 :
351 0 : uint8_t *spice_marshaller_add_by_ref_full(SpiceMarshaller *m, uint8_t *data, size_t size,
352 : spice_marshaller_item_free_func free_data, void *opaque)
353 : {
354 : MarshallerItem *item;
355 : SpiceMarshallerData *d;
356 :
357 0 : if (data == NULL || size == 0) {
358 0 : return NULL;
359 : }
360 :
361 0 : item = spice_marshaller_add_item(m);
362 0 : item->data = data;
363 0 : item->len = size;
364 0 : item->free_data = free_data;
365 0 : item->opaque = opaque;
366 :
367 0 : d = m->data;
368 0 : m->total_size += size;
369 0 : d->total_size += size;
370 :
371 0 : return data;
372 : }
373 :
374 0 : uint8_t *spice_marshaller_add(SpiceMarshaller *m, const uint8_t *data, size_t size)
375 : {
376 : uint8_t *ptr;
377 :
378 0 : ptr = spice_marshaller_reserve_space(m, size);
379 0 : memcpy(ptr, data, size);
380 0 : return ptr;
381 : }
382 :
383 0 : uint8_t *spice_marshaller_add_by_ref(SpiceMarshaller *m, const uint8_t *data, size_t size)
384 : {
385 : /* the cast to no-const here is safe as data is used for writing only if
386 : * free_data pointer is not NULL
387 : */
388 0 : return spice_marshaller_add_by_ref_full(m, (uint8_t *) data, size, NULL, NULL);
389 : }
390 :
391 0 : void spice_marshaller_add_chunks_by_ref(SpiceMarshaller *m, SpiceChunks *chunks)
392 : {
393 : unsigned int i;
394 :
395 0 : for (i = 0; i < chunks->num_chunks; i++) {
396 0 : spice_marshaller_add_by_ref(m, chunks->chunk[i].data,
397 0 : chunks->chunk[i].len);
398 : }
399 0 : }
400 :
401 1 : SpiceMarshaller *spice_marshaller_get_submarshaller(SpiceMarshaller *m)
402 : {
403 : SpiceMarshallerData *d;
404 : SpiceMarshaller *m2;
405 :
406 1 : d = m->data;
407 :
408 1 : m2 = spice_new(SpiceMarshaller, 1);
409 1 : spice_marshaller_init(m2, d);
410 :
411 1 : d->last_marshaller->next = m2;
412 1 : d->last_marshaller = m2;
413 :
414 1 : return m2;
415 : }
416 :
417 1 : SpiceMarshaller *spice_marshaller_get_ptr_submarshaller(SpiceMarshaller *m)
418 : {
419 : SpiceMarshaller *m2;
420 : uint8_t *p;
421 : int size;
422 :
423 1 : size = 4;
424 :
425 1 : p = spice_marshaller_reserve_space(m, size);
426 1 : memset(p, 0, size);
427 1 : m2 = spice_marshaller_get_submarshaller(m);
428 1 : m2->pointer_ref.marshaller = m;
429 1 : m2->pointer_ref.item_nr = m->n_items - 1;
430 1 : m2->pointer_ref.offset = m->items[m->n_items - 1].len - size;
431 :
432 1 : return m2;
433 : }
434 :
435 1 : static uint8_t *lookup_ref(MarshallerRef *ref)
436 : {
437 : MarshallerItem *item;
438 :
439 1 : item = &ref->marshaller->items[ref->item_nr];
440 1 : return item->data + ref->offset;
441 : }
442 :
443 :
444 0 : void spice_marshaller_set_base(SpiceMarshaller *m, size_t base)
445 : {
446 : /* Only supported for root marshaller */
447 0 : assert(m->data->marshallers == m);
448 :
449 0 : m->data->base = base;
450 0 : }
451 :
452 3 : uint8_t *spice_marshaller_linearize(SpiceMarshaller *m, size_t skip_bytes,
453 : size_t *len, int *free_res)
454 : {
455 : MarshallerItem *item;
456 : uint8_t *res, *p;
457 : int i;
458 :
459 : /* Only supported for root marshaller */
460 3 : assert(m->data->marshallers == m);
461 :
462 3 : if (m->n_items == 1 && m->next == NULL) {
463 2 : *free_res = FALSE;
464 2 : if (m->items[0].len <= skip_bytes) {
465 0 : *len = 0;
466 0 : return NULL;
467 : }
468 2 : *len = m->items[0].len - skip_bytes;
469 2 : return m->items[0].data + skip_bytes;
470 : }
471 :
472 1 : *free_res = TRUE;
473 1 : res = (uint8_t *)spice_malloc(m->data->total_size - skip_bytes);
474 1 : *len = m->data->total_size - skip_bytes;
475 1 : p = res;
476 :
477 : do {
478 4 : for (i = 0; i < m->n_items; i++) {
479 2 : item = &m->items[i];
480 :
481 2 : if (item->len <= skip_bytes) {
482 0 : skip_bytes -= item->len;
483 0 : continue;
484 : }
485 2 : memcpy(p, item->data + skip_bytes, item->len - skip_bytes);
486 2 : p += item->len - skip_bytes;
487 2 : skip_bytes = 0;
488 : }
489 2 : m = m->next;
490 2 : } while (m != NULL);
491 :
492 1 : return res;
493 : }
494 :
495 0 : uint8_t *spice_marshaller_get_ptr(SpiceMarshaller *m)
496 : {
497 0 : return m->items[0].data;
498 : }
499 :
500 1 : size_t spice_marshaller_get_offset(SpiceMarshaller *m)
501 : {
502 : SpiceMarshaller *m2;
503 : size_t offset;
504 :
505 1 : offset = 0;
506 1 : m2 = m->data->marshallers;
507 2 : while (m2 != m) {
508 1 : offset += m2->total_size;
509 1 : m2 = m2->next;
510 : }
511 1 : return offset - m->data->base;
512 : }
513 :
514 0 : size_t spice_marshaller_get_size(SpiceMarshaller *m)
515 : {
516 0 : return m->total_size;
517 : }
518 :
519 0 : size_t spice_marshaller_get_total_size(SpiceMarshaller *m)
520 : {
521 0 : return m->data->total_size;
522 : }
523 :
524 2 : void spice_marshaller_flush(SpiceMarshaller *m)
525 : {
526 : SpiceMarshaller *m2;
527 : uint8_t *ptr_pos;
528 :
529 : /* Only supported for root marshaller */
530 2 : assert(m->data->marshallers == m);
531 :
532 5 : for (m2 = m; m2 != NULL; m2 = m2->next) {
533 3 : if (m2->pointer_ref.marshaller != NULL && m2->total_size > 0) {
534 1 : ptr_pos = lookup_ref(&m2->pointer_ref);
535 1 : write_uint32(ptr_pos, spice_marshaller_get_offset(m2));
536 : }
537 : }
538 2 : }
539 :
540 : #ifdef WIN32
541 : // this definition is ABI compatible with WSABUF
542 : struct iovec {
543 : unsigned long iov_len;
544 : void *iov_base;
545 : };
546 : #endif
547 :
548 0 : int spice_marshaller_fill_iovec(SpiceMarshaller *m, struct iovec *vec,
549 : int n_vec, size_t skip_bytes)
550 : {
551 : MarshallerItem *item;
552 : int v, i;
553 :
554 : /* Only supported for root marshaller */
555 0 : assert(m->data->marshallers == m);
556 :
557 0 : v = 0;
558 : do {
559 0 : for (i = 0; i < m->n_items; i++) {
560 0 : item = &m->items[i];
561 :
562 0 : if (item->len <= skip_bytes) {
563 0 : skip_bytes -= item->len;
564 0 : continue;
565 : }
566 0 : if (v == n_vec) {
567 0 : return v; /* Not enough space in vec */
568 : }
569 0 : vec[v].iov_base = (uint8_t *)item->data + skip_bytes;
570 0 : vec[v].iov_len = item->len - skip_bytes;
571 0 : skip_bytes = 0;
572 0 : v++;
573 : }
574 0 : m = m->next;
575 0 : } while (m != NULL);
576 :
577 0 : return v;
578 : }
579 :
580 2 : void *spice_marshaller_add_uint64(SpiceMarshaller *m, uint64_t v)
581 : {
582 : uint8_t *ptr;
583 :
584 2 : ptr = spice_marshaller_reserve_space(m, sizeof(uint64_t));
585 2 : write_uint64(ptr, v);
586 2 : return (void *)ptr;
587 : }
588 :
589 0 : void *spice_marshaller_add_int64(SpiceMarshaller *m, int64_t v)
590 : {
591 : uint8_t *ptr;
592 :
593 0 : ptr = spice_marshaller_reserve_space(m, sizeof(int64_t));
594 0 : write_int64(ptr, v);
595 0 : return (void *)ptr;
596 : }
597 :
598 3 : void *spice_marshaller_add_uint32(SpiceMarshaller *m, uint32_t v)
599 : {
600 : uint8_t *ptr;
601 :
602 3 : ptr = spice_marshaller_reserve_space(m, sizeof(uint32_t));
603 3 : write_uint32(ptr, v);
604 3 : return (void *)ptr;
605 : }
606 :
607 0 : void spice_marshaller_set_uint32(SPICE_GNUC_UNUSED SpiceMarshaller *m, void *ref, uint32_t v)
608 : {
609 0 : write_uint32((uint8_t *)ref, v);
610 0 : }
611 :
612 0 : void *spice_marshaller_add_int32(SpiceMarshaller *m, int32_t v)
613 : {
614 : uint8_t *ptr;
615 :
616 0 : ptr = spice_marshaller_reserve_space(m, sizeof(int32_t));
617 0 : write_int32(ptr, v);
618 0 : return (void *)ptr;
619 : }
620 :
621 4 : void *spice_marshaller_add_uint16(SpiceMarshaller *m, uint16_t v)
622 : {
623 : uint8_t *ptr;
624 :
625 4 : ptr = spice_marshaller_reserve_space(m, sizeof(uint16_t));
626 4 : write_uint16(ptr, v);
627 4 : return (void *)ptr;
628 : }
629 :
630 0 : void *spice_marshaller_add_int16(SpiceMarshaller *m, int16_t v)
631 : {
632 : uint8_t *ptr;
633 :
634 0 : ptr = spice_marshaller_reserve_space(m, sizeof(int16_t));
635 0 : write_int16(ptr, v);
636 0 : return (void *)ptr;
637 : }
638 :
639 2 : void *spice_marshaller_add_uint8(SpiceMarshaller *m, uint8_t v)
640 : {
641 : uint8_t *ptr;
642 :
643 2 : ptr = spice_marshaller_reserve_space(m, sizeof(uint8_t));
644 2 : write_uint8(ptr, v);
645 2 : return (void *)ptr;
646 : }
647 :
648 0 : void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v)
649 : {
650 : uint8_t *ptr;
651 :
652 0 : ptr = spice_marshaller_reserve_space(m, sizeof(int8_t));
653 0 : write_int8(ptr, v);
654 0 : return (void *)ptr;
655 : }
656 :
657 0 : void spice_marshaller_add_fd(SpiceMarshaller *m, int fd)
658 : {
659 0 : spice_assert(m->has_fd == false);
660 :
661 0 : m->has_fd = true;
662 0 : if (fd != -1) {
663 0 : m->fd = dup(fd);
664 0 : if (m->fd == -1) {
665 0 : perror("dup");
666 : }
667 : } else {
668 0 : m->fd = -1;
669 : }
670 0 : }
671 :
672 0 : bool spice_marshaller_get_fd(SpiceMarshaller *m, int *fd)
673 : {
674 0 : bool had_fd = m->has_fd;
675 :
676 0 : *fd = m->fd;
677 0 : m->has_fd = false;
678 :
679 0 : return had_fd;
680 : }
|