void wl_connection_sync(struct wl_connection *connection) { uint32_t p[2]; struct wl_buffer *b; int size, avail, head; b = &connection->in; size = sizeof p; do { head = connection->in.head; if (head < b->tail) avail = ARRAY_LENGTH(b->data) - (b->tail - head); else avail = head - b->tail; if (avail < size) wl_connection_data(connection, WL_CONNECTION_READABLE); else if (size == sizeof p) { /* If the header is available, get the full size. */ wl_connection_copy(connection, p, sizeof p); size = p[1] >> 16; } } while (avail < size); }
WL_EXPORT void wl_display_iterate(struct wl_display *display, uint32_t mask) { uint32_t p[2], opcode, size; int len; len = wl_connection_data(display->connection, mask); while (len > 0) { if (len < sizeof p) break; wl_connection_copy(display->connection, p, sizeof p); opcode = p[1] & 0xffff; size = p[1] >> 16; if (len < size) break; handle_event(display, p[0], opcode, size); len -= size; } if (len < 0) { fprintf(stderr, "read error: %m\n"); exit(EXIT_FAILURE); } }
static int queue_event(struct wl_display *display, int len) { uint32_t p[2], id; int opcode, size; struct wl_proxy *proxy; struct wl_closure *closure; const struct wl_message *message; struct wl_event_queue *queue; wl_connection_copy(display->connection, p, sizeof p); id = p[0]; opcode = p[1] & 0xffff; size = p[1] >> 16; if (len < size) return 0; proxy = wl_map_lookup(&display->objects, id); if (proxy == WL_ZOMBIE_OBJECT) { wl_connection_consume(display->connection, size); return size; } else if (proxy == NULL) { wl_connection_consume(display->connection, size); return size; } message = &proxy->object.interface->events[opcode]; closure = wl_connection_demarshal(display->connection, size, &display->objects, message); if (!closure) return -1; if (create_proxies(proxy, closure) < 0) { wl_closure_destroy(closure); return -1; } if (wl_closure_lookup_objects(closure, &display->objects) != 0) { wl_closure_destroy(closure); return -1; } increase_closure_args_refcount(closure); proxy->refcount++; closure->proxy = proxy; if (proxy == &display->proxy) queue = &display->display_queue; else queue = proxy->queue; if (wl_list_empty(&queue->event_list)) pthread_cond_signal(&queue->cond); wl_list_insert(queue->event_list.prev, &closure->link); return size; }
static void handle_event(struct wl_display *display, uint32_t id, uint32_t opcode, uint32_t size) { if (size < 4096) { uint32_t *p = alloca (size); wl_connection_copy(display->connection, p, size); if (display->event_handler != NULL) display->event_handler(display, id, opcode, p[2], p[3], display->event_handler_data); } wl_connection_consume(display->connection, size); }
struct wl_closure * wl_connection_demarshal(struct wl_connection *connection, uint32_t size, struct wl_map *objects, const struct wl_message *message) { uint32_t *p, *next, *end, length, id; int fd; char *s; unsigned int i, count, num_arrays; const char *signature; struct argument_details arg; struct wl_closure *closure; struct wl_array *array, *array_extra; count = arg_count_for_signature(message->signature); if (count > WL_CLOSURE_MAX_ARGS) { wl_log("too many args (%d)\n", count); errno = EINVAL; wl_connection_consume(connection, size); return NULL; } num_arrays = wl_message_count_arrays(message); closure = malloc(sizeof *closure + size + num_arrays * sizeof *array); if (closure == NULL) { errno = ENOMEM; wl_connection_consume(connection, size); return NULL; } array_extra = closure->extra; p = (uint32_t *)(closure->extra + num_arrays); end = p + size / sizeof *p; wl_connection_copy(connection, p, size); closure->sender_id = *p++; closure->opcode = *p++ & 0x0000ffff; signature = message->signature; for (i = 0; i < count; i++) { signature = get_next_argument(signature, &arg); if (arg.type != 'h' && p + 1 > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } switch (arg.type) { case 'u': closure->args[i].u = *p++; break; case 'i': closure->args[i].i = *p++; break; case 'f': closure->args[i].f = *p++; break; case 's': length = *p++; if (length == 0) { closure->args[i].s = NULL; break; } next = p + DIV_ROUNDUP(length, sizeof *p); if (next > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } s = (char *) p; if (length > 0 && s[length - 1] != '\0') { wl_log("string not nul-terminated, " "message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } closure->args[i].s = s; p = next; break; case 'o': id = *p++; closure->args[i].n = id; if (id == 0 && !arg.nullable) { wl_log("NULL object received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } break; case 'n': id = *p++; closure->args[i].n = id; if (id == 0 && !arg.nullable) { wl_log("NULL new ID received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } if (wl_map_reserve_new(objects, id) < 0) { wl_log("not a valid new object id (%u), " "message %s(%s)\n", id, message->name, message->signature); errno = EINVAL; goto err; } break; case 'a': length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); if (next > end) { wl_log("message too short, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } array_extra->size = length; array_extra->alloc = 0; array_extra->data = p; closure->args[i].a = array_extra++; p = next; break; case 'h': if (connection->fds_in.tail == connection->fds_in.head) { wl_log("file descriptor expected, " "object (%d), message %s(%s)\n", closure->sender_id, message->name, message->signature); errno = EINVAL; goto err; } wl_buffer_copy(&connection->fds_in, &fd, sizeof fd); connection->fds_in.tail += sizeof fd; closure->args[i].h = fd; break; default: wl_abort("unknown type\n"); break; } } closure->count = count; closure->message = message; wl_connection_consume(connection, size); return closure; err: wl_closure_destroy(closure); wl_connection_consume(connection, size); return NULL; }
struct wl_closure * wl_connection_demarshal(struct wl_connection *connection, uint32_t size, struct wl_map *objects, const struct wl_message *message) { uint32_t *p, *next, *end, length, **id; int *fd; char *extra, **s; unsigned int i, count, extra_space; const char *signature = message->signature; struct argument_details arg; struct wl_object **object; struct wl_array **array; struct wl_closure *closure; count = arg_count_for_signature(signature) + 2; if (count > ARRAY_LENGTH(closure->types)) { printf("too many args (%d)\n", count); errno = EINVAL; wl_connection_consume(connection, size); return NULL; } extra_space = wl_message_size_extra(message); closure = malloc(sizeof *closure + 8 + size + extra_space); if (closure == NULL) return NULL; closure->message = message; closure->types[0] = &ffi_type_pointer; closure->types[1] = &ffi_type_pointer; closure->start = closure->buffer; wl_connection_copy(connection, closure->buffer, size); p = &closure->buffer[2]; end = (uint32_t *) ((char *) p + size); extra = (char *) end; for (i = 2; i < count; i++) { signature = get_next_argument(signature, &arg); if (p + 1 > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } switch (arg.type) { case 'u': closure->types[i] = &ffi_type_uint32; closure->args[i] = p++; break; case 'i': closure->types[i] = &ffi_type_sint32; closure->args[i] = p++; break; case 'f': closure->types[i] = &ffi_type_sint32; closure->args[i] = p++; break; case 's': closure->types[i] = &ffi_type_pointer; length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); if (next > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } s = (char **) extra; extra += sizeof *s; closure->args[i] = s; if (length == 0) { *s = NULL; } else { *s = (char *) p; } if (length > 0 && (*s)[length - 1] != '\0') { printf("string not nul-terminated, " "message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } p = next; break; case 'o': closure->types[i] = &ffi_type_pointer; object = (struct wl_object **) extra; extra += sizeof *object; closure->args[i] = object; if (*p == 0 && !arg.nullable) { printf("NULL new ID received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); *object = NULL; errno = EINVAL; goto err; } *object = wl_map_lookup(objects, *p); if (*object == WL_ZOMBIE_OBJECT) { /* references object we've already * destroyed client side */ *object = NULL; } else if (*object == NULL && *p != 0) { printf("unknown object (%u), message %s(%s)\n", *p, message->name, message->signature); *object = NULL; errno = EINVAL; goto err; } if (*object != NULL && message->types[i-2] != NULL && (*object)->interface != message->types[i-2]) { printf("invalid object (%u), type (%s), " "message %s(%s)\n", *p, (*object)->interface->name, message->name, message->signature); errno = EINVAL; goto err; } p++; break; case 'n': closure->types[i] = &ffi_type_pointer; id = (uint32_t **) extra; extra += sizeof *id; closure->args[i] = id; *id = p; if (*id == 0 && !arg.nullable) { printf("NULL new ID received on non-nullable " "type, message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } if (wl_map_reserve_new(objects, *p) < 0) { printf("not a valid new object id (%d), " "message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } p++; break; case 'a': closure->types[i] = &ffi_type_pointer; length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); if (next > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } array = (struct wl_array **) extra; extra += sizeof *array; closure->args[i] = array; *array = (struct wl_array *) extra; extra += sizeof **array; (*array)->size = length; (*array)->alloc = 0; (*array)->data = p; p = next; break; case 'h': closure->types[i] = &ffi_type_sint; fd = (int *) extra; extra += sizeof *fd; closure->args[i] = fd; wl_buffer_copy(&connection->fds_in, fd, sizeof *fd); connection->fds_in.tail += sizeof *fd; break; default: printf("unknown type\n"); assert(0); break; } } closure->count = i; ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI, closure->count, &ffi_type_void, closure->types); wl_connection_consume(connection, size); return closure; err: closure->count = i; wl_closure_destroy(closure); wl_connection_consume(connection, size); return NULL; }
int wl_connection_demarshal_mem(struct wl_connection *connection, struct wl_hash *objects, void *dest, size_t dsize, const char *types, ...) { uint32_t id; int size; size_t field_ofs, field_size, field_align; const char *c; union wl_element value; struct wl_object *object; uint32_t data[64], *p; va_list va; #define alignof(type) offsetof (struct { char c; type i; }, i) va_start (va, types); for (field_ofs = 0, c = types; *c && *c != '|'; ) { switch (*c) { case 'i': value.uint32 = va_arg (va, int); c++; field_size = sizeof (int); field_align = alignof (int); break; case 'p': value.object = va_arg (va, void *); c++; field_size = sizeof (void *); field_align = alignof (void *); break; case 's': value.object = va_arg (va, char *); value.object = strdup (value.object); c++; field_size = sizeof (char *); field_align = alignof (char *); break; case 'o': id = va_arg (va, int); object = wl_hash_lookup(objects, id); if (object == NULL) printf("unknown object (%d)\n", id); c++; value.object = object; field_size = sizeof (void *); field_align = alignof (void *); break; #if 0 case '{': id = va_arg (va, int); object = wl_hash_lookup(objects, id); if (object == NULL) printf("unknown object (%d)\n", id); c++; if (!strchrcmp (&c, '}', object->interface->name)) printf("wrong object type\n"); value.object = object; field_size = sizeof (void *); field_align = alignof (void *); break; #endif case 'O': value.new_id = id = va_arg (va, int); if (objects != NULL) { object = wl_hash_lookup(objects, id); if (object != NULL) printf("object already exists (%d)\n", id); } c++; field_size = sizeof (int); field_align = alignof (int); break; default: printf("unknown type %c\n", *c++); continue; } field_ofs = (field_ofs + field_align - 1) & -field_align; if (field_ofs > dsize) { printf("not enough memory"); return -1; } memcpy ((char *)dest + field_ofs, &value, field_size); field_ofs += field_size; } if (*c == '|') c++; if (connection) { wl_connection_copy(connection, data, 2 * sizeof (data[0])); id = data[0]; size = data[1] >> 16; if (sizeof data < size) { printf("request too big, should malloc tmp buffer here\n"); return -1; } wl_connection_copy(connection, data, size); wl_connection_consume(connection, size); } else
struct wl_closure * wl_connection_demarshal(struct wl_connection *connection, uint32_t size, struct wl_hash_table *objects, const struct wl_message *message) { uint32_t *p, *next, *end, length; int *fd; char *extra, **s; int i, count, extra_space; struct wl_object **object; struct wl_array **array; struct wl_closure *closure = &connection->receive_closure; count = strlen(message->signature) + 2; if (count > ARRAY_LENGTH(closure->types)) { printf("too many args (%d)\n", count); assert(0); } extra_space = wl_message_size_extra(message); if (sizeof closure->buffer < size + extra_space) { printf("request too big, should malloc tmp buffer here\n"); assert(0); } closure->message = message; closure->types[0] = &ffi_type_pointer; closure->types[1] = &ffi_type_pointer; wl_connection_copy(connection, closure->buffer, size); p = &closure->buffer[2]; end = (uint32_t *) ((char *) (p + size)); extra = (char *) end; for (i = 2; i < count; i++) { if (p + 1 > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } switch (message->signature[i - 2]) { case 'u': closure->types[i] = &ffi_type_uint32; closure->args[i] = p++; break; case 'i': closure->types[i] = &ffi_type_sint32; closure->args[i] = p++; break; case 's': closure->types[i] = &ffi_type_pointer; length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); if (next > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } s = (char **) extra; extra += sizeof *s; closure->args[i] = s; if (length == 0) { *s = NULL; } else { *s = (char *) p; } if (length > 0 && (*s)[length - 1] != '\0') { printf("string not nul-terminated, " "message %s(%s)\n", message->name, message->signature); errno = EINVAL; goto err; } p = next; break; case 'o': closure->types[i] = &ffi_type_pointer; object = (struct wl_object **) extra; extra += sizeof *object; closure->args[i] = object; *object = wl_hash_table_lookup(objects, *p); if (*object == NULL && *p != 0) { printf("unknown object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } p++; break; case 'n': closure->types[i] = &ffi_type_uint32; closure->args[i] = p; object = wl_hash_table_lookup(objects, *p); if (object != NULL) { printf("not a new object (%d), " "message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } p++; break; case 'a': closure->types[i] = &ffi_type_pointer; length = *p++; next = p + DIV_ROUNDUP(length, sizeof *p); if (next > end) { printf("message too short, " "object (%d), message %s(%s)\n", *p, message->name, message->signature); errno = EINVAL; goto err; } array = (struct wl_array **) extra; extra += sizeof *array; closure->args[i] = array; *array = (struct wl_array *) extra; extra += sizeof **array; (*array)->size = length; (*array)->alloc = 0; (*array)->data = p; p = next; break; case 'h': closure->types[i] = &ffi_type_sint; fd = (int *) extra; extra += sizeof *fd; closure->args[i] = fd; wl_buffer_copy(&connection->fds_in, fd, sizeof *fd); connection->fds_in.tail += sizeof *fd; break; default: printf("unknown type\n"); assert(0); break; } } closure->count = i; ffi_prep_cif(&closure->cif, FFI_DEFAULT_ABI, closure->count, &ffi_type_uint32, closure->types); wl_connection_consume(connection, size); return closure; err: closure->count = i; wl_closure_destroy(closure); return NULL; }