void *lo_message_serialise(lo_message m, const char *path, void *to, size_t * size) { int i, argc; char *types, *ptr; size_t s = lo_message_length(m, path); if (size) { *size = s; } if (!to) { to = calloc(1, s); } memset((char *) to + lo_strsize(path) - 4, 0, 4); // ensure zero-padding strcpy(to, path); memset((char *) to + lo_strsize(path) + lo_strsize(m->types) - 4, 0, 4); strcpy((char *) to + lo_strsize(path), m->types); types = m->types + 1; ptr = (char *) to + lo_strsize(path) + lo_strsize(m->types); memcpy(ptr, m->data, m->datalen); argc = m->typelen - 1; for (i = 0; i < argc; ++i) { size_t len = lo_arg_size(types[i], ptr); lo_arg_network_endian(types[i], ptr); ptr += len; } return to; }
int lo_coerce(lo_type type_to, lo_arg * to, lo_type type_from, lo_arg * from) { if (type_to == type_from) { memcpy(to, from, lo_arg_size(type_from, from)); return 1; } if (lo_is_string_type(type_to) && lo_is_string_type(type_from)) { strcpy((char *) to, (char *) from); return 1; } if (lo_is_numerical_type(type_to) && lo_is_numerical_type(type_from)) { switch (type_to) { case LO_INT32: to->i = (uint32_t) lo_hires_val(type_from, from); break; case LO_INT64: to->i64 = (uint64_t) lo_hires_val(type_from, from); break; case LO_FLOAT: to->f = (float) lo_hires_val(type_from, from); break; case LO_DOUBLE: to->d = (double) lo_hires_val(type_from, from); break; default: fprintf(stderr, "liblo: bad coercion: %c -> %c\n", type_from, type_to); return 0; } return 1; } return 0; }
void lo_message_pp(lo_message m) { void *d = m->data; void *end = m->data + m->datalen; int i; printf("%s ", m->types); for (i = 1; m->types[i]; i++) { if (i > 1) { printf(" "); } lo_arg_pp_internal(m->types[i], d, 1); d += lo_arg_size(m->types[i], d); } putchar('\n'); if (d != end) { fprintf(stderr, "liblo warning: type and data do not match (off by %d) in message %p\n", abs(d - end), m); } }
void lo_arg_pp_internal(lo_type type, void *data, int bigendian) { lo_pcast32 val32; lo_pcast64 val64; int size; int i; size = lo_arg_size(type, data); if (size == 4 || type == LO_BLOB) { if (bigendian) { val32.nl = lo_otoh32(*(int32_t *)data); } else { val32.nl = *(int32_t *)data; } } else if (size == 8) { if (bigendian) { val64.nl = lo_otoh64(*(int64_t *)data); } else { val64.nl = *(int64_t *)data; } } switch (type) { case LO_INT32: printf("%d", val32.i); break; case LO_FLOAT: printf("%f", val32.f); break; case LO_STRING: printf("\"%s\"", (char *)data); break; case LO_BLOB: printf("["); if (val32.i > 12) { printf("%d byte blob", val32.i); } else { printf("%db ", val32.i); for (i=0; i<val32.i; i++) { printf("0x%02x", *((char *)(data) + 4 + i)); if (i+1 < val32.i) printf(" "); } } printf("]"); break; case LO_INT64: printf("%lld", val64.i); break; case LO_TIMETAG: printf("%08x.%08x", val64.tt.sec, val64.tt.frac); break; case LO_DOUBLE: printf("%f", val64.f); break; case LO_SYMBOL: printf("'%s", (char *)data); break; case LO_CHAR: printf("'%c'", (char)val32.c); break; case LO_MIDI: printf("MIDI ["); for (i=0; i<4; i++) { printf("0x%02x", *((uint8_t *)(data) + i)); if (i+1 < 4) printf(" "); } printf("]"); break; case LO_TRUE: printf("#T"); break; case LO_FALSE: printf("#F"); break; case LO_NIL: printf("Nil"); break; case LO_INFINITUM: printf("Infinitum"); break; default: fprintf(stderr, "liblo warning: unhandled type: %c\n", type); break; } }
static void dispatch_method(lo_server s, const char *path, char *types, void *data) { int argc = strlen(types); lo_arg **argv = NULL; lo_method it; int ret = 1; int err; int endian_fixed = 0; int pattern = strpbrk(path, " #*,?[]{}") != NULL; lo_message msg = lo_message_new(); lo_address src = lo_address_new(NULL, NULL); char hostname[LO_HOST_SIZE]; char portname[32]; const char *pptr; free(msg->types); msg->types = types; msg->typelen = strlen(types); msg->typesize = 0; msg->data = data; msg->datalen = 0; msg->datasize = 0; msg->source = src; //inet_ntop(s->addr.ss_family, &s->addr.padding, hostname, sizeof(hostname)); if (s->protocol == LO_UDP) { err = getnameinfo((struct sockaddr *)&s->addr, sizeof(s->addr), hostname, sizeof(hostname), portname, sizeof(portname), NI_NUMERICHOST | NI_NUMERICSERV); if (err) { switch (err) { case EAI_AGAIN: lo_throw(s, err, "Try again", path); break; case EAI_BADFLAGS: lo_throw(s, err, "Bad flags", path); break; case EAI_FAIL: lo_throw(s, err, "Failed", path); break; case EAI_FAMILY: lo_throw(s, err, "Cannot resolve address family", path); break; case EAI_MEMORY: lo_throw(s, err, "Out of memory", path); break; case EAI_NONAME: lo_throw(s, err, "Cannot resolve", path); break; #ifndef WIN32 case EAI_SYSTEM: lo_throw(s, err, strerror(err), path); break; #endif default: lo_throw(s, err, "Unknown error", path); break; } return; } } else { hostname[0] = '\0'; portname[0] = '\0'; } free(src->host); free(src->port); src->host = hostname; src->port = portname; src->proto = s->protocol; for (it = s->first; it; it = it->next) { /* If paths match or handler is wildcard */ if (!it->path || !strcmp(path, it->path) || (pattern && lo_pattern_match(it->path, path))) { /* If types match or handler is wildcard */ if (!it->typespec || !strcmp(types, it->typespec)) { if (!argv && *types) { int i; char *ptr = types - 1 + lo_strsize(types - 1); argv = calloc(argc + 1, sizeof(lo_arg *)); if (!endian_fixed) { for (i=0; i<argc; i++) { argv[i] = (lo_arg *)ptr; lo_arg_host_endian(types[i], ptr); ptr += lo_arg_size(types[i], ptr); } endian_fixed = 1; } } /* Send wildcard path to generic handler, expanded path to others. */ pptr = path; if (it->path) pptr = it->path; ret = it->handler(pptr, types, argv, argc, msg, it->user_data); } else if (lo_can_coerce_spec(types, it->typespec)) { int i; int opsize = 0; char *ptr = types - 1 + lo_strsize(types - 1); char *data_co, *data_co_ptr; argv = calloc(argc+1, sizeof(lo_arg *)); for (i=0; i<argc; i++) { opsize += lo_arg_size(it->typespec[i], ptr); ptr += lo_arg_size(types[i], ptr); } data_co = malloc(opsize); data_co_ptr = data_co; ptr = types - 1 + lo_strsize(types - 1); for (i=0; i<argc; i++) { argv[i] = (lo_arg *)data_co_ptr; if (!endian_fixed) { lo_arg_host_endian(types[i], ptr); } lo_coerce(it->typespec[i], (lo_arg *)data_co_ptr, types[i], (lo_arg *)ptr); data_co_ptr += lo_arg_size(it->typespec[i], data_co_ptr); ptr += lo_arg_size(types[i], ptr); } endian_fixed = 1; /* Send wildcard path to generic handler, expanded path to others. */ pptr = path; if (it->path) pptr = it->path; ret = it->handler(pptr, it->typespec, argv, argc, msg, it->user_data); free(argv); free(data_co); argv = NULL; } if (ret == 0 && !pattern) { break; } } } /* If we find no matching methods, check for protocol level stuff */ if (ret == 1 && s->protocol == LO_UDP) { char *pos = strrchr(path, '/'); /* if its a method enumeration call */ if (pos && *(pos+1) == '\0') { lo_message reply = lo_message_new(); int len = strlen(path); lo_strlist *sl = NULL, *slit, *slnew, *slend; if (!strcmp(types, "i")) { lo_message_add_int32(reply, argv[0]->i); } lo_message_add_string(reply, path); for (it = s->first; it; it = it->next) { /* If paths match */ if (it->path && !strncmp(path, it->path, len)) { char *tmp; char *sec; tmp = malloc(strlen(it->path + len) + 1); strcpy(tmp, it->path + len); #ifdef WIN32 sec = strchr(tmp,'/'); #else sec = index(tmp, '/'); #endif if (sec) *sec = '\0'; slend = sl; for (slit = sl; slit; slend = slit, slit = slit->next) { if (!strcmp(slit->str, tmp)) { free(tmp); tmp = NULL; break; } } if (tmp) { slnew = calloc(1, sizeof(lo_strlist)); slnew->str = tmp; slnew->next = NULL; if (!slend) { sl = slnew; } else { slend->next = slnew; } } } } for (slit = sl; slit; slit = slit->next) { lo_message_add_string(reply, slit->str); free(slit->str); } lo_send_message(src, "#reply", reply); lo_message_free(reply); } } free(argv); /* the address got assigned static stuff, hence not using address_free */ free(src); /* these are already part of data and will be freed later */ msg->data = NULL; msg->types = NULL; lo_message_free(msg); }