static int dispatch_queued(lo_server s) { char *path, *types, *data; queued_msg_list *head = s->queued; queued_msg_list *tailhead; lo_timetag disp_time; if (!head) { lo_throw(s, LO_INT_ERR, "attempted to dispatch with empty queue", "timeout"); return 1; } disp_time = head->ts; do { tailhead = head->next; path = ((queued_msg_list *)s->queued)->data; types = path + lo_strsize(path) + 1; data = types + lo_strsize(types); dispatch_method(s, path, types, data); free(((queued_msg_list *)s->queued)->data); free((queued_msg_list *)s->queued); s->queued = tailhead; head = tailhead; } while (head && lo_timetag_diff(head->ts, disp_time) < FLT_EPSILON); return 0; }
size_t lo_arg_size(lo_type type, void *data) { 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 4; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: return 8; case LO_STRING: case LO_SYMBOL: return lo_strsize((char *)data); case LO_BLOB: return lo_blobsize((lo_blob)data); default: fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); return 0; } return 0; }
void lo_message_add_symbol(lo_message m, const char *a) { const int size = lo_strsize(a); char *nptr = lo_message_add_data(m, size); lo_message_add_typechar(m, LO_SYMBOL); strncpy(nptr, a, size); }
void lo_message_add_string(lo_message m, const char *a) { const int size = lo_strsize(a); char *nptr = lo_message_add_data(m, size); lo_message_add_typechar(m, LO_STRING); strncpy(nptr, a, size); }
void *lo_message_serialise(lo_message m, const char *path, void *to, size_t *size) { size_t s = lo_message_length(m, path); if (size) { *size = s; } if (!to) { to = calloc(1, s); } strcpy(to, path); strcpy(to + lo_strsize(path), m->types); memcpy(to + lo_strsize(path) + lo_strsize(m->types), m->data, m->datalen); return to; }
int lo_message_add_symbol(lo_message m, const char *a) { const int size = lo_strsize(a); char *nptr = lo_message_add_data(m, size); if (!nptr) return -1; if (lo_message_add_typechar(m, LO_SYMBOL)) return -1; strncpy(nptr, a, size); return 0; }
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; }
size_t lo_message_length(lo_message m, const char *path) { return lo_strsize(path) + lo_strsize(m->types) + m->datalen; }
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); }
int lo_server_recv(lo_server s) { void *data; size_t size; char *path; char *types; double sched_time = lo_server_next_event_delay(s); #ifdef WIN32 fd_set ps; struct timeval stimeout; int res; #else struct pollfd ps; #endif again: if (sched_time > 0.01) { if (sched_time > 10.0) { sched_time = 10.0; } #ifdef WIN32 if(!initWSock()) return 0; ps.fd_count = 1; ps.fd_array[0] = s->socket; stimeout.tv_sec = sched_time; stimeout.tv_usec = (sched_time-stimeout.tv_sec)*1.e6; res = select(1,&ps,NULL,NULL,&stimeout); if(res == SOCKET_ERROR) { return 0; } if(!res) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) { goto again; } return dispatch_queued(s); } #else ps.fd = s->socket; ps.events = POLLIN | POLLPRI | POLLERR | POLLHUP; ps.revents = 0; poll(&ps, 1, (int)(sched_time * 1000.0)); if (ps.revents == POLLERR || ps.revents == POLLHUP) { return 0; } if (!ps.revents) { sched_time = lo_server_next_event_delay(s); if (sched_time > 0.01) { goto again; } return dispatch_queued(s); } #endif } else { return dispatch_queued(s); } if (s->protocol == LO_TCP) { data = lo_server_recv_raw_stream(s, &size); } else { data = lo_server_recv_raw(s, &size); } if (!data) { return 0; } path = data; types = data + lo_strsize(path); if (!strcmp(path, "#bundle")) { char *pos = types; uint32_t len; lo_timetag ts, now; lo_timetag_now(&now); ts.sec = lo_otoh32(*((uint32_t *)pos)); pos += 4; ts.frac = lo_otoh32(*((uint32_t *)pos)); pos += 4; while (pos - (char *)data < size) { len = lo_otoh32(*((uint32_t *)pos)); pos += 4; /* test for immedaite dispatch */ if ((ts.sec == 0 && ts.frac == 1) || lo_timetag_diff(ts, now) <= 0.0) { types = pos + lo_strsize(pos); dispatch_method(s, pos, types + 1, types + lo_strsize(types)); } else { queue_data(s, ts, pos, len); } pos += len; } free(data); return size; } else if (*types != ',') { lo_throw(s, LO_ENOTYPE, "Missing typetag", path); return -1; } dispatch_method(s, path, types+1, data); free(data); return size; }