I am evaluating libuv as a library for a C/c++ server that I am writing. The protocol is length prefixed so as soon as I can read a 32 bit integer from the stream I should be able to tell what size of buffer I should allocate. The documentation says that the uv_read_start function might be called multiple times.
UV_EXTERN int uv_read_start(uv_stream_t*, uv_alloc_cb alloc_cb,
uv_read_cb read_cb);
Since I am using a length prefixed protocol, once I know the right size of the buffer I would like to allocate it and re use it for subsequent reads till I have received all my bytes. Is there an easy way to do this with libuv? Right now it seems like the uv_alloc_cb function has to take care of this. Can I associate a buffer with my stream object instead of putting it in a map or something?
Since I am using a length prefixed protocol, I would not like to allocate a buffer on the heap at all till I can read the first 4 bytes (32 bits). Is it possible for me to allocate on the stack a buffer of size 4 and have the uv_read_cb function actually do the heap allocation? Is the uv_read_cb function invoked synchronously as part of the uv_read_start function? If it is then seems like I should be able to allocate on the stack when I know that I don't already have a buffer attached to my stream.
Answering my own question. I found the answers on the libuv mailing list here: https://groups.google.com/forum/#!topic/libuv/fRNQV_QGgaA
Copying the details here if the link becomes unavailable:
Attaching your own data structure to a handle:
The handle has a
void* data
field that is yours to use. You can make it point it to an auxiliary structure where you store the length and the buffer.Alternatively, you can embed the uv_tcp_t in another structure, then look up the embedding structure with container_of. It's not a standard C macro but you can find its definition and usage examples in the libuv/ source tree. Its benefit is that it just does some pointer arithmetic, it saves you from another level of pointer indirection.
Stack allocation for the receiving buffer:
No, that's not possible. The proper way of thinking about it is that your alloc_cb returns a buffer that libuv will fill with data sometime in the future. The stress is on "sometime" because there are no guarantees when that will happen; it may be immediate, it may be seconds (or minutes) away.