On Thu, Nov 11, 2010 at 10:42 PM, Kevin Bowling <kevin.bowl...@kev009.com> wrote: > Hi, > > I've seen a few mails talking about evbuffer_peek, but no solid usage of > it. The doxygen on the libevent page doesn't cover it generating my own > from 2.0.8 has shed little light on its use to me.
There's an example at http://www.wangafu.net/~nickm/libevent-book/Ref7_evbuffer.html that might give more detail. > Basically, for my test case I have two bytes in network order that make up a > short. These are one byte into the buffer. > > uint16_t ulen; > struct evbuffer_ptr bufpos; > struct evbuffer_iovec bufvec[2]; > > if (evbuffer_ptr_set(input, &bufpos, 1, EVBUFFER_PTR_SET) < 0) > return(-1); // Add proper error handling > if (evbuffer_peek(input, 2, &bufpos, bufvec, 1) < 0) > return(-1); // Add proper error handling > > ulen = ntohs((uint16_t)bufvec[0].iov_base); > > I've tried using many variations with the pointers. I can't even read out > each byte individually. What am I doing wrong? bufvec[0].iov_base is a pointer to char *; if you cast that to a uint16_t, you'll get junk. When I change the line to ulen = ntohs(*(uint16_t*)bufvec[0].iov_base); it works fine for me. But really, that's not quite good enough, for two reasons. First, nothing in the C standard says that unaligned accesses are okay, and iov_base is a pointer into the evbuffer's internal memory, so you can't count on it being 16-bit aligned. Instead you might be better off doing... memcpy(&ulen, bufvec[0].iov_base, 2); ulen = ntohs(ulen); But that's not enough either, since it is possible that the result of evbuffer_peek -- even if it's only two bytes long -- could be split across multiple iovecs. So instead you need to change the stuff starting with the peek to something more like: int n; n = evbuffer_peek(input, 2, &bufpos, bufvec, 1); if (n<0) return -1; /* add error handling */ if (n == 1) { /* It all fit in bufvec[0] */ memcpy(&ulen, bufvec[0].iov_base, 2); ulen = ntohs(ulen); } else { assert(n == 2); /* two bytes can't be split across more than 2 chunks. */ ulen = *(uint8_t*)bufvec[0].iov_base; ulen <<= 8; ulen |= *(uint8_t*)bufvec[1].iov_base; } Ugly? You bet! evbuffer_peek is really only optimized for the case where you do not want to take any performance hit for copying data out of the evbuffer, and you're willing to make your code more complex because of it. Instead, I'd suggest evbuffer_copyout(), which is way easier for what you seem to be doing: uint8_t tmp[3]; if (evbuffer_copyout(input, tmp, 3) < 3) return -1; ulen = (tmp[1]<<8) | tmp[2]; hth, -- Nick *********************************************************************** To unsubscribe, send an e-mail to majord...@freehaven.net with unsubscribe libevent-users in the body.