diff --git a/src/modules/rtp/rtp-native.c b/src/modules/rtp/rtp-native.c index 86760a627..d1a3911d7 100644 --- a/src/modules/rtp/rtp-native.c +++ b/src/modules/rtp/rtp-native.c @@ -200,7 +200,6 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ uint32_t ssrc; uint8_t payload; unsigned cc; - ssize_t r; uint8_t aux[1024]; bool found_tstamp = false; @@ -209,6 +208,15 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ pa_memchunk_reset(chunk); + /* FIONREAD works on both BSD and Linux, but they do something different: + * - on Linux it returns the amount of bytes in the next datagram + * - on BSDs it returns the total amount of bytes in the output buffer; this can be + * more than one datagram and includes headers + * + * So the result will be a lower bound of how many bytes are needed, but might not be + * the exact size of the buffer size needed. + */ + if (ioctl(c->fd, FIONREAD, &size) < 0) { pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; @@ -238,6 +246,9 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ size = 1; } + /* Since size is a lower bound, also constrain it to an upper bound */ + size = PA_MIN(size, 1<<16); + if (c->recv_buf_size < (size_t) size) { do c->recv_buf_size *= 2; @@ -259,12 +270,11 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ m.msg_controllen = sizeof(aux); m.msg_flags = 0; - r = recvmsg(c->fd, &m, 0); - - if (r != size) { - if (r < 0 && errno != EAGAIN && errno != EINTR) - pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + size = recvmsg(c->fd, &m, 0); + if (size < 0) { + if (errno != EAGAIN && errno != EINTR) + pa_log_warn("recvmsg() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 8614022f8..00a648057 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -146,15 +146,25 @@ int pa_sap_recv(pa_sap_context *c, bool *goodbye) { char *buf = NULL, *e; uint32_t header; unsigned six, ac, k; - ssize_t r; - + pa_assert(c); pa_assert(goodbye); + /* FIONREAD works on both BSD and Linux, but they do something different: + * - on Linux it returns the amount of bytes in the next datagram + * - on BSDs it returns the total amount of bytes in the output buffer; this can be + * more than one datagram and includes headers + * + * So the result will be a lower bound of how many bytes are needed, but might not be + * the exact size of the buffer size needed. + */ + if (ioctl(c->fd, FIONREAD, &size) < 0) { pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } + /* Since size is a lower bound, also constrain it to an upper bound */ + size = PA_MIN(size, 1<<16); buf = pa_xnew(char, (unsigned) size+1); buf[size] = 0; @@ -170,8 +180,8 @@ int pa_sap_recv(pa_sap_context *c, bool *goodbye) { m.msg_controllen = 0; m.msg_flags = 0; - if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + if ((size = recvmsg(c->fd, &m, 0)) < 0) { + pa_log_warn("recvmsg() failed: %s", pa_cstrerror(errno)); goto fail; }