static int coerce_arg_to_int(lo_type type, lo_arg *src) { lo_arg dst; if (!lo_coerce(LO_INT32, &dst, type, src)) return -1; src->i = dst.i; return 0; }
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); }