ssize_t lo_validate_arg(lo_type type, void *data, ssize_t size) { if (size < 0) { return -1; } switch (type) { case LO_TRUE: case LO_FALSE: case LO_NIL: case LO_INFINITUM: return 0; case LO_INT32: case LO_FLOAT: case LO_MIDI: case LO_CHAR: return size >= 4 ? 4 : -LO_ESIZE; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: return size >= 8 ? 8 : -LO_ESIZE; case LO_STRING: case LO_SYMBOL: return lo_validate_string((char *) data, size); case LO_BLOB: return lo_validate_blob((lo_blob) data, size); default: return -LO_EINVALIDTYPE; } return -LO_INT_ERR; }
ssize_t lo_validate_bundle(void *data, ssize_t size) { ssize_t len = 0, remain = size; char *pos = data; ssize_t elem_len; len = lo_validate_string(data, size); if (len < 0) { return -LO_ESIZE; // invalid size } if (0 != strcmp(data, "#bundle")) { return -LO_EINVALIDBUND; // not a bundle } pos += len; remain -= len; // time tag if (remain < 8) { return -LO_ESIZE; } pos += 8; remain -= 8; while (remain >= 4) { elem_len = lo_otoh32(*((uint32_t *) pos)); pos += 4; remain -= 4; if (elem_len > remain) { return -LO_ESIZE; } pos += elem_len; remain -= elem_len; } if (0 != remain) { return -LO_ESIZE; } return size; }
lo_message lo_message_deserialise(void *data, size_t size, int *result) { lo_message msg = NULL; char *types = NULL, *ptr = NULL; int i = 0, argc = 0, remain = size, res = 0, len; if (remain <= 0) { res = LO_ESIZE; goto fail; } msg = malloc(sizeof(struct _lo_message)); if (!msg) { res = LO_EALLOC; goto fail; } msg->types = NULL; msg->typelen = 0; msg->typesize = 0; msg->data = NULL; msg->datalen = 0; msg->datasize = 0; msg->source = NULL; msg->argv = NULL; msg->ts = LO_TT_IMMEDIATE; msg->refcount = 0; // path len = lo_validate_string(data, remain); if (len < 0) { res = LO_EINVALIDPATH; // invalid path string goto fail; } remain -= len; // types if (remain <= 0) { res = LO_ENOTYPE; // no type tag string goto fail; } types = (char *) data + len; len = lo_validate_string(types, remain); if (len < 0) { res = LO_EINVALIDTYPE; // invalid type tag string goto fail; } if (types[0] != ',') { res = LO_EBADTYPE; // type tag string missing initial comma goto fail; } remain -= len; msg->typelen = strlen(types); msg->typesize = len; msg->types = malloc(msg->typesize); if (NULL == msg->types) { res = LO_EALLOC; goto fail; } memcpy(msg->types, types, msg->typesize); // args msg->data = malloc(remain); if (NULL == msg->data) { res = LO_EALLOC; goto fail; } memcpy(msg->data, types + len, remain); msg->datalen = msg->datasize = remain; ptr = msg->data; ++types; argc = msg->typelen - 1; if (argc) { msg->argv = calloc(argc, sizeof(lo_arg *)); if (NULL == msg->argv) { res = LO_EALLOC; goto fail; } } for (i = 0; remain >= 0 && i < argc; ++i) { len = lo_validate_arg((lo_type) types[i], ptr, remain); if (len < 0) { res = LO_EINVALIDARG; // invalid argument goto fail; } lo_arg_host_endian((lo_type) types[i], ptr); msg->argv[i] = len ? (lo_arg *) ptr : NULL; remain -= len; ptr += len; } if (0 != remain || i != argc) { res = LO_ESIZE; // size/argument mismatch goto fail; } if (result) { *result = res; } return msg; fail: if (msg) { lo_message_free(msg); } if (result) { *result = res; } return NULL; }
char *lo_get_path(void *data, ssize_t size) { ssize_t result = lo_validate_string(data, size); return (result >= 4) ? (char *) data : NULL; }
int lo_server_dispatch_data(lo_server s, void *data, size_t size) { int result = 0; char *path = data; ssize_t len = lo_validate_string(data, size); if (len < 0) { lo_throw(s, -len, "Invalid message path", NULL); return len; } if (!strcmp(data, "#bundle")) { char *pos; int remain; uint32_t elem_len; lo_timetag ts, now; ssize_t bundle_result = lo_validate_bundle(data, size); if (bundle_result < 0) { lo_throw(s, -bundle_result, "Invalid bundle", NULL); return bundle_result; } pos = (char *)data + len; remain = size - len; lo_timetag_now(&now); ts.sec = lo_otoh32(*((uint32_t *)pos)); pos += 4; ts.frac = lo_otoh32(*((uint32_t *)pos)); pos += 4; remain -= 8; while (remain >= 4) { lo_message msg; elem_len = lo_otoh32(*((uint32_t *)pos)); pos += 4; remain -= 4; msg = lo_message_deserialise(pos, elem_len, &result); if (!msg) { lo_throw(s, result, "Invalid bundle element received", path); return -result; } // set timetag from bundle msg->ts = ts; // test for immediate dispatch if ((ts.sec == LO_TT_IMMEDIATE.sec && ts.frac == LO_TT_IMMEDIATE.frac) || lo_timetag_diff(ts, now) <= 0.0) { dispatch_method(s, pos, msg); lo_message_free(msg); } else { queue_data(s, ts, pos, msg); } pos += elem_len; remain -= elem_len; } } else { lo_message msg = lo_message_deserialise(data, size, &result); if (NULL == msg) { lo_throw(s, result, "Invalid message received", path); return -result; } dispatch_method(s, data, msg); lo_message_free(msg); } return size; }