/* * Try and write() to the socket, whatever doesn't get written * append to the buffer... for a host with a fast net connection, * this prevents an unnecessary copy of the data * (the socket is non-blocking, so we won't hang) */ void sbappend(PNATState pData, struct socket *so, struct mbuf *m) { int ret = 0; int mlen = 0; STAM_PROFILE_START(&pData->StatIOSBAppend_pf, a); LogFlow(("sbappend: so = %lx, m = %lx, m->m_len = %d\n", (long)so, (long)m, m ? m->m_len : 0)); STAM_COUNTER_INC(&pData->StatIOSBAppend); /* Shouldn't happen, but... e.g. foreign host closes connection */ mlen = m_length(m, NULL); if (mlen <= 0) { STAM_COUNTER_INC(&pData->StatIOSBAppend_zm); goto done; } /* * If there is urgent data, call sosendoob * if not all was sent, sowrite will take care of the rest * (The rest of this function is just an optimisation) */ if (so->so_urgc) { sbappendsb(pData, &so->so_rcv, m); m_freem(pData, m); sosendoob(so); return; } /* * We only write if there's nothing in the buffer, * otherwise it'll arrive out of order, and hence corrupt */ if (so->so_rcv.sb_cc == 0) { caddr_t buf = NULL; if (m->m_next) { buf = RTMemAlloc(mlen); if (buf == NULL) { ret = 0; goto no_sent; } m_copydata(m, 0, mlen, buf); } else buf = mtod(m, char *); ret = send(so->s, buf, mlen, 0); if (m->m_next) RTMemFree(buf); }
/* * Try and write() to the socket, whatever doesn't get written * append to the buffer... for a host with a fast net connection, * this prevents an unnecessary copy of the data * (the socket is non-blocking, so we won't hang) */ void sbappend(struct socket *so, struct mbuf *m) { int ret = 0; DEBUG_CALL("sbappend"); DEBUG_ARG("so = %lx", (long)so); DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("m->m_len = %d", m->m_len); /* Shouldn't happen, but... e.g. foreign host closes connection */ if (m->m_len <= 0) { m_free(m); return; } /* * If there is urgent data, call sosendoob * if not all was sent, sowrite will take care of the rest * (The rest of this function is just an optimisation) */ if (so->so_urgc) { sbappendsb(&so->so_rcv, m); m_free(m); sosendoob(so); return; } /* * We only write if there's nothing in the buffer, * ottherwise it'll arrive out of order, and hence corrupt */ if (!so->so_rcv.sb_cc) ret = send(so->s, m->m_data, m->m_len, 0); if (ret <= 0) { /* * Nothing was written * It's possible that the socket has closed, but * we don't need to check because if it has closed, * it will be detected in the normal way by soread() */ sbappendsb(&so->so_rcv, m); } else if (ret != m->m_len) { /* * Something was written, but not everything.. * sbappendsb the rest */ m->m_len -= ret; m->m_data += ret; sbappendsb(&so->so_rcv, m); } /* else */ /* Whatever happened, we free the mbuf */ m_free(m); }
/* * Write data from so_rcv to so's socket, * updating all sbuf field as necessary */ int sowrite(struct socket *so) { int n,nn; struct sbuf *sb = &so->so_rcv; int len = sb->sb_cc; struct iovec iov[2]; DEBUG_CALL("sowrite"); DEBUG_ARG("so = %lx", (long)so); if (so->so_urgc) { sosendoob(so); if (sb->sb_cc == 0) return 0; } /* * No need to check if there's something to write, * sowrite wouldn't have been called otherwise */ iov[0].iov_base = sb->sb_rptr; iov[1].iov_base = NULL; iov[1].iov_len = 0; if (sb->sb_rptr < sb->sb_wptr) { iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; /* Should never succeed, but... */ if (iov[0].iov_len > len) iov[0].iov_len = len; n = 1; } else { iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; 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_wptr - sb->sb_data; if (iov[1].iov_len > len) iov[1].iov_len = len; n = 2; } else n = 1; } /* Check if there's urgent data to send, and if so, send it */ #ifdef HAVE_READV nn = writev(so->s, (const struct iovec *)iov, n); DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #else nn = slirp_send(so, iov[0].iov_base, iov[0].iov_len,0); #endif /* This should never happen, but people tell me it does *shrug* */ if (nn < 0 && (errno == EAGAIN || errno == EINTR)) return 0; if (nn <= 0) { DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", so->so_state, errno)); sofcantsendmore(so); tcp_sockclosed(sototcpcb(so)); return -1; } #ifndef HAVE_READV if (n == 2 && nn == iov[0].iov_len) { int ret; ret = slirp_send(so, iov[1].iov_base, iov[1].iov_len,0); if (ret > 0) nn += ret; } DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); #endif /* Update sbuf */ sb->sb_cc -= nn; sb->sb_rptr += nn; if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) sb->sb_rptr -= sb->sb_datalen; /* * If in DRAIN mode, and there's no more data, set * it CANTSENDMORE */ if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) sofcantsendmore(so); return nn; }
/* re-use off */ off = (sb->sb_data + sb->sb_datalen) - from; if (off > len) off = len; memcpy(to, from, off); len -= off; if (len) memcpy(to+off, sb->sb_data, len); } } #else /* VBOX_WITH_SLIRP_BSD_SBUF */ void sbappend (PNATState pData, struct socket *so, struct mbuf *m) { int ret = 0; int mlen = 0; caddr_t buf = NULL; STAM_PROFILE_START(&pData->StatIOSBAppend_pf, a); LogFlow(("sbappend: so = %R[natsock], m = %lx, m->m_len = %d\n", so, (long)m, m ? m->m_len : 0)); STAM_COUNTER_INC(&pData->StatIOSBAppend); mlen = m_length(m, NULL); if (mlen <= 0) { STAM_COUNTER_INC(&pData->StatIOSBAppend_zm); goto done; } /* * We only write if there's nothing in the buffer, * ottherwise it'll arrive out of order, and hence corrupt */ buf = RTMemAlloc(mlen); if (buf == NULL) { ret = 0; goto no_sent; } m_copydata(m, 0, mlen, buf); /* * If there is urgent data, call sosendoob * if not all was sent, sowrite will take care of the rest * (The rest of this function is just an optimisation) */ if (so->so_urgc) { sbuf_bcpy(&so->so_rcv, buf, mlen); RTMemFree(buf); m_free(pData, m); sosendoob(so); return; } if(!sbuf_len(&so->so_rcv)) ret = send(so->s, buf, mlen, 0); no_sent: if (ret <= 0) { STAM_COUNTER_INC(&pData->StatIOSBAppend_wf); /* * Nothing was written * It's possible that the socket has closed, but * we don't need to check because if it has closed, * it will be detected in the normal way by soread() */ sbuf_bcpy(&so->so_rcv, buf, mlen); STAM_PROFILE_STOP(&pData->StatIOSBAppend_pf_wf, a); goto done; } else if (ret != mlen) { STAM_COUNTER_INC(&pData->StatIOSBAppend_wp); /* * Something was written, but not everything.. * sbappendsb the rest */ sbuf_bcpy(&so->so_rcv, &buf[ret + 1], mlen - ret); STAM_PROFILE_STOP(&pData->StatIOSBAppend_pf_wp, a); goto done; } /* else */ /* Whatever happened, we free the mbuf */ STAM_COUNTER_INC(&pData->StatIOSBAppend_wa); STAM_PROFILE_STOP(&pData->StatIOSBAppend_pf_wa, a); done: RTMemFree(buf); m_freem(pData, m); }