soread(so) struct socket *so; { int n, nn, lss, total; struct sbuf *sb = &so->so_snd; int len = sb->sb_datalen - sb->sb_cc; struct iovec iov[2]; int mss = so->so_tcpcb->t_maxseg; DEBUG_CALL("soread"); DEBUG_ARG("so = %lx", (long )so); /* * No need to check if there's enough room to read. * soread wouldn't have been called if there weren't */ len = sb->sb_datalen - sb->sb_cc; iov[0].iov_base = sb->sb_wptr; if (sb->sb_wptr < sb->sb_rptr) { iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; len -= iov[0].iov_len; if (len) { iov[1].iov_base = sb->sb_data; iov[1].iov_len = sb->sb_rptr - sb->sb_data; if(iov[1].iov_len > len) iov[1].iov_len = len; total = iov[0].iov_len + iov[1].iov_len; if (total > mss) { lss = total%mss; if (iov[1].iov_len > lss) { iov[1].iov_len -= lss; n = 2; } else { lss -= iov[1].iov_len; iov[0].iov_len -= lss; n = 1; } } else n = 2; } else { if (iov[0].iov_len > mss) iov[0].iov_len -= iov[0].iov_len%mss; n = 1; } } #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #else nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); #endif if (nn <= 0) { if (nn < 0 && (errno == EINTR || errno == EAGAIN)) return 0; else { DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); sofcantrcvmore(so); tcp_sockclosed(sototcpcb(so)); return -1; } } #ifndef HAVE_READV /* * If there was no error, try and read the second time round * We read again if n = 2 (ie, there's another part of the buffer) * and we read as much as we could in the first read * We don't test for <= 0 this time, because there legitimately * might not be any more data (since the socket is non-blocking), * a close will be detected on next iteration. * A return of -1 wont (shouldn't) happen, since it didn't happen above */ if (n == 2 && nn == iov[0].iov_len) nn += recv(so->s, iov[1].iov_base, iov[1].iov_len,0); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #endif /* Update fields */ sb->sb_cc += nn; sb->sb_wptr += nn; if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_wptr -= sb->sb_datalen; return nn; }