oscpy
oscpy copied to clipboard
Blob size unpack_from with wrong unit
Describe the bug
I am sending an OSC message containing a single blob of data:
/destn/1\x00\x00\x00\x00,b\x00\x00\x00\x00\x00\x08...
[28 bytes] /destn/1 b [8]0123456789ABCDEF
I am getting this result for both OSC data send from C and using Dart.
To Reproduce Code example showing the issue is the example code from the readme:
from oscpy.server import OSCThreadServer
from time import sleep
osc = OSCThreadServer()
sock = osc.listen(address='0.0.0.0', port=9000, default=True)
@osc.address(b'/destn/*')
def callback(*values):
print("got values: {}".format(values))
sleep(1000)
osc.stop()
Here the sending portion in C using tinyosc compiled with gcc *.c -Werror -std=c99 -O0 -g -o sendosc
Note: main.c from tinyosc has to be removed or the content be replaced with below:
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include "tinyosc.h"
int main(int argc, char *argv[]) {
char buffer[128];
int len = 0;
char blob[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF};
len = tosc_writeMessage(buffer, sizeof(buffer), "/destn/1", "b",
sizeof(blob), blob);
tosc_printOscBuffer(buffer, len);
struct sockaddr_in client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(9000);
client_addr.sin_addr.s_addr = INADDR_ANY;
const int fd_send = socket(AF_INET, SOCK_DGRAM, 0);
if (fd_send < 0)
{
fprintf(stderr, "Error opening socket");
return -1;
}
int response = sendto(
fd_send, (void*) &buffer[0], len, 0,
(struct sockaddr*)&client_addr, sizeof(client_addr)
);
if (response < 0) {
fprintf(stderr, "Error in sendto()\n");
return -1;
}
// close the UDP socket
close(fd_send);
return 0;
}
Expected behavior
Read the correct size of the blob and get a binary array same way it was written.
The same message works without any issue using e.g. python-osc.
blob = b'\x01#Eg\x89\xab\xcd\xef'
Logs/output
Exception in thread Thread-1:
Traceback (most recent call last):
File "miniconda3/envs/v/lib/python3.9/threading.py", line 973, in _bootstrap_inner
self.run()
File "miniconda3/envs/v/lib/python3.9/threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "miniconda3/envs/v/lib/python3.9/site-packages/oscpy/server.py", line 338, in _run_listener
self._listen()
File "miniconda3/envs/v/lib/python3.9/site-packages/oscpy/server.py", line 386, in _listen
for address, tags, values, offset in read_packet(
File "miniconda3/envs/v/lib/python3.9/site-packages/oscpy/parser.py", line 409, in read_packet
read_message(
File "miniconda3/envs/v/lib/python3.9/site-packages/oscpy/parser.py", line 309, in read_message
value, off = parse(
File "miniconda3/envs/v/lib/python3.9/site-packages/oscpy/parser.py", line 206, in parse
return parser(
File "miniconda3/envs/v/lib/python3.9/site-packages/oscpy/parser.py", line 96, in parse_blob
data = unpack_from('>%iQ' % length, value, offset + size)
struct.error: unpack_from requires a buffer of at least 84 bytes for unpacking 64 bytes at offset 20 (actual buffer size is 28)
^CTraceback (most recent call last):
File "Documents/code/udp_test/osc_example.py", line 11, in <module>
sleep(1000)
KeyboardInterrupt
Platform (please complete the following information):
- OS: OSX 12.5.1
- Python 3.9
- OSCpy 0.6.0 (installed with pip)
Additional context Add any other context about the problem here.
When parsing the blob, why do you use an integer (>%iQ) instead of a char (>%cQ)?
From osc.parser:
def parse_blob(value, offset=0, **kwargs):
"""Return a blob from offset in value."""
size = calcsize('>i')
length = unpack_from('>i', value, offset)[0]
data = unpack_from('>%iQ' % length, value, offset + size)
return data, padded(length, 8)
The specification says:
OSC-blob An int32 size count, followed by that many 8-bit bytes of arbitrary binary data, followed by 0-3 additional zero bytes to make the total number of bits a multiple of 32.
I think the line where the data is unpacked should be something like:
data = unpack_from('>%ic' % length value, offset + size)
Seems like a bug indeed, i didn’t put a lot of attention in the project since i don’t need it currently, but i’ll try to have a look at it, of course, if someone else has time before that, PR welcome.