[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] Using evbuffer_peek



On Thu, Nov 11, 2010 at 11:16 PM, Kevin Bowling
<kevin.bowling@xxxxxxxxxx> wrote:
>
>
> On Thu, Nov 11, 2010 at 9:00 PM, Nick Mathewson <nickm@xxxxxxxxxxxxx> wrote:
>>
>> On Thu, Nov 11, 2010 at 10:42 PM, Kevin Bowling
>> <kevin.bowling@xxxxxxxxxx> 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.
>>
>> 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];
>>
>
> Hi Nick,
>
> I've got it working with the copyout method and that works great for this
> simple case.  The one thing that wories me is that there are other variable
> length packets with internal length headers after a larger number of bytes.
>  Is there any way to offset with copyout, or would it be better to serialize
> and use a pointer or use peek with vectors?

Hm.  There isn't a copyout variant that takes an offset.  It would be
cool to add one in Libevent 2.1 [*], but for now, 2.0 is in
feature-freeze.

If you need to extract small fields that are very very far into the
buffer, you could write a helper like this:

int
my_evbuffer_copyout_from(struct evbuffer *b, void *buf,
                         size_t len, struct evbuffer_ptr *ptr)
{
    /* FIXME locking is left as an exercise for the reader */
    /* FIXME This is totally untested. I'm not even sure if it compiles */
    struct evbuffer_iovec *v;
    int nvecs, i;
    char *cp = buf;

    if (!ptr)
      return evbuffer_copyout(b, buf, len);

    if (evbuffer_get_length(b) < ptr->pos + len)
      return -1;  /* not enough data */

    if (ptr->pos + len < 128) {
      /* XXX Not sure if this optimization helps */
      char tmp[128];
      evbuffer_copyout(b, tmp, ptr->pos + len);
      memcpy(buf, tmp+ptr->pos, len);
      return 0;
    }

    /* determine how many vecs we need */
    nvecs = evbuffer_peek(b, len, ptr, NULL, 0);
    if (nvecs < 1)
      return -1;
    v = calloc(sizeof(struct evbuffer_iovec), nvecs);
    if (v == NULL)
      return -1;

    if (evbuffer_peek(b, len, ptr, v, nvecs) < 0) {
      free(v);
      return -1; /* should be impossible, but let's take no chances */
    }

    for (i = 0; i < nvecs; ++i) {
      if (v[i].iov_len <= len) {
        memcpy(cp, v[i].iov_base, v[i].iov_len);
        cp += v[i].iov_len;
        len -= v[i].iov_len;
      } else {
        memcpy(cp, v[i].iov_base, len);
        break;
      }
    }
    free(v);
    return 0;
}


[*] If somebody adds a ticket to the "feature requests" tracker at
https://sourceforge.net/tracker/?group_id=50884&atid=461325

-- 
Nick
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.