Fix logic in correcting high values from FIONREAD

The old logic made sense back when buffer.c was an enormous linear
buffer, but it doesn't make any sense for the chain-based
implementation.

This patch also refactors the ioctl{socket}? call into its own function.
This commit is contained in:
Nick Mathewson 2010-05-28 15:05:32 -04:00
parent 0798dd1247
commit 3467f2fa3b

View File

@ -1856,13 +1856,31 @@ _evbuffer_read_setup_vecs(struct evbuffer *buf, ev_ssize_t howmuch,
return i; return i;
} }
static int
get_n_bytes_readable_on_socket(evutil_socket_t fd)
{
#if defined(FIONREAD) && defined(WIN32)
unsigned long lng = EVBUFFER_MAX_READ;
if (ioctlsocket(fd, FIONREAD, &lng) < 0)
return -1;
return (int)lng;
#elif defined(FIONREAD)
int n = EVBUFFER_MAX_READ;
if (ioctl(fd, FIONREAD, &n) < 0)
return -1;
return n;
#else
return EVBUFFER_MAX_READ;
#endif
}
/* TODO(niels): should this function return ev_ssize_t and take ev_ssize_t /* TODO(niels): should this function return ev_ssize_t and take ev_ssize_t
* as howmuch? */ * as howmuch? */
int int
evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch) evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
{ {
struct evbuffer_chain *chain, **chainp; struct evbuffer_chain *chain, **chainp;
int n = EVBUFFER_MAX_READ; int n;
int result; int result;
#ifdef USE_IOVEC_IMPL #ifdef USE_IOVEC_IMPL
@ -1870,9 +1888,6 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
#else #else
unsigned char *p; unsigned char *p;
#endif #endif
#if defined(FIONREAD) && defined(WIN32)
unsigned long lng = EVBUFFER_MAX_READ;
#endif
EVBUFFER_LOCK(buf); EVBUFFER_LOCK(buf);
@ -1883,27 +1898,9 @@ evbuffer_read(struct evbuffer *buf, evutil_socket_t fd, int howmuch)
goto done; goto done;
} }
#if defined(FIONREAD) n = get_n_bytes_readable_on_socket(fd);
#ifdef WIN32 if (n <= 0 || n > EVBUFFER_MAX_READ)
if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) <= 0) {
#else
if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
#endif
n = EVBUFFER_MAX_READ; n = EVBUFFER_MAX_READ;
} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
/*
* It's possible that a lot of data is available for
* reading. We do not want to exhaust resources
* before the reader has a chance to do something
* about it. If the reader does not tell us how much
* data we should read, we artificially limit it.
*/
if (chain == NULL || n < EVBUFFER_MAX_READ)
n = EVBUFFER_MAX_READ;
else if ((size_t)n > chain->buffer_len << 2)
n = chain->buffer_len << 2;
}
#endif
if (howmuch < 0 || howmuch > n) if (howmuch < 0 || howmuch > n)
howmuch = n; howmuch = n;