- * Implement receive operations on a socket.
- * We depend on the way that records are added to the sockbuf
- * by sbappend*. In particular, each record (mbufs linked through m_next)
- * must begin with an address if the protocol so specifies,
- * followed by an optional mbuf or mbufs containing ancillary data,
- * and then zero or more mbufs of data.
- * In order to avoid blocking network interrupts for the entire time here,
- * we splx() while doing the actual copy to user space.
+ * If we have less data than requested, block awaiting more
+ * (subject to any timeout) if:
+ * 1. the current count is less than the low water mark, or
+ * 2. MSG_WAITALL is set, and it is possible to do the entire
+ * receive operation at once if we block (resid <= hiwat).
+ * 3. MSG_DONTWAIT is not set
+ * If MSG_WAITALL is set but resid is larger than the receive buffer,
+ * we have to do the receive in sections, and thus risk returning
+ * a short count if a timeout or signal occurs after we start.
+ */
+static boolean_t
+so_should_wait(struct socket *so, struct uio *uio, struct mbuf *m, int flags)
+{
+ struct protosw *pr = so->so_proto;
+
+ /* No mbufs in the receive-queue? Wait! */
+ if (m == NULL) {
+ return true;
+ }
+
+ /* Not enough data in the receive socket-buffer - we may have to wait */
+ if ((flags & MSG_DONTWAIT) == 0 && so->so_rcv.sb_cc < uio_resid(uio) &&
+ m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0) {
+ /*
+ * Application did set the lowater-mark, so we should wait for
+ * this data to be present.
+ */
+ if (so->so_rcv.sb_cc < so->so_rcv.sb_lowat) {
+ return true;
+ }
+
+ /*
+ * Application wants all the data - so let's try to do the
+ * receive-operation at once by waiting for everything to
+ * be there.
+ */
+ if ((flags & MSG_WAITALL) && uio_resid(uio) <= so->so_rcv.sb_hiwat) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*
+ * Implement receive operations on a socket.
+ * We depend on the way that records are added to the sockbuf
+ * by sbappend*. In particular, each record (mbufs linked through m_next)
+ * must begin with an address if the protocol so specifies,
+ * followed by an optional mbuf or mbufs containing ancillary data,
+ * and then zero or more mbufs of data.
+ * In order to avoid blocking network interrupts for the entire time here,
+ * we splx() while doing the actual copy to user space.