Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/kern/uipc_socket.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.66 retrieving revision 1.66.4.2 diff -u -p -r1.66 -r1.66.4.2 --- src/sys/kern/uipc_socket.c 2002/05/07 08:06:35 1.66 +++ src/sys/kern/uipc_socket.c 2002/11/08 09:31:35 1.66.4.2 @@ -1,4 +1,4 @@ -/* $NetBSD: uipc_socket.c,v 1.66 2002/05/07 08:06:35 enami Exp $ */ +/* $NetBSD: uipc_socket.c,v 1.66.4.2 2002/11/08 09:31:35 tron Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -72,7 +72,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.66 2002/05/07 08:06:35 enami Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uipc_socket.c,v 1.66.4.2 2002/11/08 09:31:35 tron Exp $"); #include "opt_sock_counters.h" #include "opt_sosend_loan.h" @@ -797,6 +797,7 @@ soreceive(struct socket *so, struct mbuf int flags, len, error, s, offset, moff, type, orig_resid; struct protosw *pr; struct mbuf *nextrecord; + int mbuf_removed = 0; pr = so->so_proto; mp = mp0; @@ -918,6 +919,7 @@ soreceive(struct socket *so, struct mbuf m = m->m_next; } else { sbfree(&so->so_rcv, m); + mbuf_removed = 1; if (paddr) { *paddr = m; so->so_rcv.sb_mb = m->m_next; @@ -936,6 +938,7 @@ soreceive(struct socket *so, struct mbuf m = m->m_next; } else { sbfree(&so->so_rcv, m); + mbuf_removed = 1; if (controlp) { if (pr->pr_domain->dom_externalize && mtod(m, struct cmsghdr *)->cmsg_type == @@ -992,8 +995,24 @@ soreceive(struct socket *so, struct mbuf splx(s); error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); s = splsoftnet(); - if (error) + if (error) { + /* + * If any part of the record has been removed + * (such as the MT_SONAME mbuf, which will + * happen when PR_ADDR, and thus also + * PR_ATOMIC, is set), then drop the entire + * record to maintain the atomicity of the + * receive operation. + * + * This avoids a later panic("receive 1a") + * when compiled with DIAGNOSTIC. + */ + if (m && mbuf_removed + && (pr->pr_flags & PR_ATOMIC)) + (void) sbdroprecord(&so->so_rcv); + goto release; + } } else uio->uio_resid -= len; if (len == m->m_len - moff) { @@ -1054,6 +1073,23 @@ soreceive(struct socket *so, struct mbuf !sosendallatonce(so) && !nextrecord) { if (so->so_error || so->so_state & SS_CANTRCVMORE) break; + /* + * If we are peeking and the socket receive buffer is + * full, stop since we can't get more data to peek at. + */ + if ((flags & MSG_PEEK) && sbspace(&so->so_rcv) <= 0) + break; + /* + * If we've drained the socket buffer, tell the + * protocol in case it needs to do something to + * get it filled again. + */ + if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) + (*pr->pr_usrreq)(so, PRU_RCVD, + (struct mbuf *)0, + (struct mbuf *)(long)flags, + (struct mbuf *)0, + (struct proc *)0); error = sbwait(&so->so_rcv); if (error) { sbunlock(&so->so_rcv);