@@ -419,83 +419,88 @@ int qemu_parse_fd(const char *param)
* The first `offset' bytes in the iovec buffer are skipped and next
* `bytes' bytes are used.
*/
-int qemu_sendv_recvv(int sockfd, struct iovec *iov, size_t offset, size_t bytes,
- bool do_sendv)
+int qemu_sendv_recvv(int sockfd, struct iovec *iov,
+ size_t offset, size_t bytes, bool do_send)
{
- int ret, iovlen;
- size_t diff;
- struct iovec *last_iov;
-
- /* last_iov is inclusive, so count from one. */
- iovlen = 1;
- last_iov = iov;
- bytes += offset;
-
- while (last_iov->iov_len < bytes) {
- bytes -= last_iov->iov_len;
-
- last_iov++;
- iovlen++;
+ int ret;
+ struct iovec *end;
+
+ /* Find the start position, skipping `offset' bytes:
+ * first, skip all full-sized vector elements, */
+ while(offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ ++iov;
}
-
- diff = last_iov->iov_len - bytes;
- last_iov->iov_len -= diff;
-
- while (iov->iov_len <= offset) {
- offset -= iov->iov_len;
-
- iov++;
- iovlen--;
+ if (offset) {
+ /* second, skip `offset' bytes from the (now) first element,
+ * undo it on exit */
+ iov->iov_base += offset;
+ iov->iov_len -= offset;
+ }
+ /* Find the end position skipping `bytes' bytes: */
+ /* first, skip all full-sized elements */
+ end = iov;
+ while(end->iov_len <= bytes) {
+ bytes -= end->iov_len;
+ ++end;
+ }
+ if (bytes) {
+ /* second, fixup the last element, and remember
+ * the length we've cut from the end of it in `bytes' */
+ size_t tail = end->iov_len - bytes;
+ end->iov_len = bytes;
+ ++end;
+ bytes = tail;
}
-
- iov->iov_base = (char *) iov->iov_base + offset;
- iov->iov_len -= offset;
{
#if defined CONFIG_IOVEC && defined CONFIG_POSIX
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
- msg.msg_iovlen = iovlen;
-
+ msg.msg_iovlen = end - iov;;
do {
- if (do_sendv) {
- ret = sendmsg(sockfd, &msg, 0);
- } else {
- ret = recvmsg(sockfd, &msg, 0);
- }
- } while (ret == -1 && errno == EINTR);
+ ret = do_send
+ ? sendmsg(sockfd, &msg, 0)
+ : recvmsg(sockfd, &msg, 0);
+ } while (ret < 0 && errno == EINTR);
#else
- struct iovec *p = iov;
+ /* else send piece-by-piece */
+ /*XXX Note: windows has WSASend() and WSARecv() */
+ struct iovec *p = iov;
ret = 0;
- while (iovlen > 0) {
- int rc;
- if (do_sendv) {
- rc = send(sockfd, p->iov_base, p->iov_len, 0);
- } else {
- rc = qemu_recv(sockfd, p->iov_base, p->iov_len, 0);
- }
- if (rc == -1) {
- if (errno == EINTR) {
- continue;
- }
+ while(p < end) {
+ int r = do_send
+ ? send(sockfd, p->iov_base, p->iov_len, 0)
+ : qemu_recv(sockfd, p->iov_base, p->iov_len, 0);
+ if (r > 0) {
+ ret += r;
+ ++i;
+ } else if (!r) {
+ break;
+ } else if (errno == EINTR) {
+ continue;
+ } else {
+ /* else it is some "other" error,
+ * only return if there was no data processed. */
if (ret == 0) {
ret = -1;
}
break;
- }
- if (rc == 0) {
- break;
- }
- ret += rc;
- iovlen--, p++;
+ }
}
#endif
}
/* Undo the changes above */
- iov->iov_base = (char *) iov->iov_base - offset;
- iov->iov_len += offset;
- last_iov->iov_len += diff;
+ if (offset) {
+ iov->iov_base -= offset;
+ iov->iov_len += offset;
+ }
+ if (bytes) {
+ --end;
+ end->iov_len += bytes;
+ }
+
return ret;
}
@@ -206,7 +206,7 @@ int qemu_pipe(int pipefd[2]);
* the beginning of iovec but at byte position `offset'.
*/
int qemu_sendv_recvv(int sockfd, struct iovec *iov,
- size_t offset, size_t bytes, bool do_sendv);
+ size_t offset, size_t bytes, bool do_send);
#define qemu_recvv(sockfd, iov, offset, bytes) \
qemu_sendv_recvv(sockfd, iov, offset, bytes, false)
#define qemu_sendv(sockfd, iov, offset, bytes) \
Make it much more understandable, and add comments to it. This is in order to prepare similar function for writev_readv(). The new implementation has been extensively tested by splitting a large buffer into many small randomly-sized chunks, sending it over socket to another, slow process and verifying the receiving data is the same. Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> --- cutils.c | 119 +++++++++++++++++++++++++++++--------------------------- qemu-common.h | 2 +- 2 files changed, 63 insertions(+), 58 deletions(-)