void lo_arg_host_endian(lo_type type, void *data) { switch (type) { case LO_INT32: case LO_FLOAT: case LO_BLOB: case LO_CHAR: *(int32_t *)data = lo_otoh32(*(int32_t *)data); break; case LO_INT64: case LO_TIMETAG: case LO_DOUBLE: *(int64_t *)data = lo_otoh64(*(int64_t *)data); break; case LO_STRING: case LO_SYMBOL: case LO_MIDI: case LO_TRUE: case LO_FALSE: case LO_NIL: case LO_INFINITUM: /* these are fine */ break; default: fprintf(stderr, "liblo warning: unhandled OSC type '%c' at %s:%d\n", type, __FILE__, __LINE__); break; } }
ssize_t lo_validate_blob(void *data, ssize_t size) { ssize_t i, end, len; uint32_t dsize; char *pos = (char *) data; if (size < 0) { return -LO_ESIZE; // invalid size } dsize = lo_otoh32(*(uint32_t *) data); if (dsize > LO_MAX_MSG_SIZE) { // avoid int overflow in next step return -LO_ESIZE; } end = sizeof(uint32_t) + dsize; // end of data len = 4 * ((end + 3) / 4); // full padded size if (len > size) { return -LO_ESIZE; // would overflow buffer } for (i = end; i < len; ++i) { if (pos[i] != '\0') { return -LO_EPAD; // non-zero char found in pad area } } return len; }
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; }
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; } }
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; }
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; }