/* * Read from so's socket into sb_snd, updating all relevant sbuf fields * NOTE: This will only be called if it is select()ed for reading, so * a read() of 0 (or less) means it's disconnected */ int soread(struct socket *so) { int n, nn; struct sbuf *sb = &so->so_snd; struct iovec iov[2]; 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 */ sopreprbuf(so, iov, &n); #ifdef HAVE_READV nn = readv(so->s, (struct iovec *)iov, n); DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); #else nn = qemu_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) { int ret; ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0); if (ret > 0) nn += ret; } 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; }
size_t slirp_socket_can_recv(int addr_low_byte, int guest_port) { struct iovec iov[2]; struct socket *so; if (!link_up) return 0; so = slirp_find_ctl_socket(addr_low_byte, guest_port); if (!so || so->so_state & SS_NOFDREF) return 0; if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) return 0; return sopreprbuf(so, iov, NULL); }
int soreadbuf(struct socket *so, const char *buf, int size) { int n, nn, copy = size; struct sbuf *sb = &so->so_snd; struct iovec iov[2]; DEBUG_CALL("soreadbuf"); 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 */ if (sopreprbuf(so, iov, &n) < size) goto err; nn = MIN(iov[0].iov_len, copy); memcpy(iov[0].iov_base, buf, nn); copy -= nn; buf += nn; if (copy == 0) goto done; memcpy(iov[1].iov_base, buf, copy); done: /* Update fields */ sb->sb_cc += size; sb->sb_wptr += size; if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_wptr -= sb->sb_datalen; return size; err: sofcantrcvmore(so); tcp_sockclosed(sototcpcb(so)); fprintf(stderr, "soreadbuf buffer to small"); return -1; }