I have a problem that should be fairly common for app-level protocol 
implementations over libevent. I need to send a stream of messages of different 
types and sizes over a TCP connection managed by a bufferevent. The format of 
each message on the wire is <length><type><body>, where <length> is a 4-byte 
length of the message, <type> is a single-byte message type, <body> is the rest 
of the message. Every message object in my code knows how to serialize itself 
into an evbuffer, calculating and returning the length of serialized content in 
the process. However, the length of the message must appear in the evbuffer 
*before* the body of message. What's the recommended way to do this with 
libevent 2.1?

I do not want to require every message object to have a function that returns 
<length> for that message, in addition to the serialization function. This will 
increase code complexity, and will somewhat reduce its efficiency, since for 
complex payloads calculating <length> may take about as much CPU as actually 
serializing the message. So far I looked at the following options:

1) evbuffer_reserve_space()/evbuffer_commit_space() looked promising, but the 
docs say appending data to evbuffer may invalidate the pointers I get back. Is 
it true even if I pass an iovec of size 1?
2) evbuffer_add_reference() will allocate a new chain, which seems too 
expensive for reserving 5 bytes on the critical path
3) serializing <body> into a separate evbuffer, then adding it to the 
bufferevent's output buffer by reference also looks expensive for 5 bytes

Ideally, what I need is evbuffer_[reserve/commit]_space() that gives me a 
pointer to a small (5-bytes) reserved segment of evbuffer, which will remain 
valid after one or more subsequent calls  to evbuffer_add() that will compose 
the body of message.

-Mark

Reply via email to