In soreceive_stream() don't drop an already dequeued mbuf chain by
overwriting the return mbuf pointer with newly received data after a loop. Instead append the new mbuf chain to the existing one. Fix up sb_lastrecord when dequeuing mbuf's so that sbappend_stream() doesn't get confused. For the remainder copy case in the mbuf delivery part deduct the copied length len instead of the whole mbuf length. Additionally don't depend on 'n' being being available which isn't true in the case of MSG_PEEK. Fix the MSG_WAITALL case by comparing against sb_hiwat. Before it was looping for every receive as sb_lowat normally is zero. Add comment about issue with (MSG_WAITALL | MSG_PEEK) which isn't properly handled. Submitted by: trociny (except for the change in last paragraph)
This commit is contained in:
parent
8d045dbdf3
commit
e8ad36aba4
@ -1962,6 +1962,7 @@ soreceive_generic(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
||||
|
||||
/*
|
||||
* Optimized version of soreceive() for stream (TCP) sockets.
|
||||
* XXXAO: (MSG_WAITALL | MSG_PEEK) isn't properly handled.
|
||||
*/
|
||||
int
|
||||
soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
||||
@ -2050,7 +2051,7 @@ soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
||||
|
||||
/* On MSG_WAITALL we must wait until all data or error arrives. */
|
||||
if ((flags & MSG_WAITALL) &&
|
||||
(sb->sb_cc >= uio->uio_resid || sb->sb_cc >= sb->sb_lowat))
|
||||
(sb->sb_cc >= uio->uio_resid || sb->sb_cc >= sb->sb_hiwat))
|
||||
goto deliver;
|
||||
|
||||
/*
|
||||
@ -2076,7 +2077,11 @@ soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
||||
if (mp0 != NULL) {
|
||||
/* Dequeue as many mbufs as possible. */
|
||||
if (!(flags & MSG_PEEK) && len >= sb->sb_mb->m_len) {
|
||||
for (*mp0 = m = sb->sb_mb;
|
||||
if (*mp0 == NULL)
|
||||
*mp0 = sb->sb_mb;
|
||||
else
|
||||
m_cat(*mp0, sb->sb_mb);
|
||||
for (m = sb->sb_mb;
|
||||
m != NULL && m->m_len <= len;
|
||||
m = m->m_next) {
|
||||
len -= m->m_len;
|
||||
@ -2084,10 +2089,11 @@ soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
||||
sbfree(sb, m);
|
||||
n = m;
|
||||
}
|
||||
n->m_next = NULL;
|
||||
sb->sb_mb = m;
|
||||
sb->sb_lastrecord = sb->sb_mb;
|
||||
if (sb->sb_mb == NULL)
|
||||
SB_EMPTY_FIXUP(sb);
|
||||
n->m_next = NULL;
|
||||
}
|
||||
/* Copy the remainder. */
|
||||
if (len > 0) {
|
||||
@ -2098,9 +2104,9 @@ soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
|
||||
if (m == NULL)
|
||||
len = 0; /* Don't flush data from sockbuf. */
|
||||
else
|
||||
uio->uio_resid -= m->m_len;
|
||||
uio->uio_resid -= len;
|
||||
if (*mp0 != NULL)
|
||||
n->m_next = m;
|
||||
m_cat(*mp0, m);
|
||||
else
|
||||
*mp0 = m;
|
||||
if (*mp0 == NULL) {
|
||||
|
Loading…
Reference in New Issue
Block a user