Amit Shah | e4d5639 | 2010-04-27 18:04:05 +0530 | [diff] [blame] | 1 | /* |
Michael Tokarev | 2278a69 | 2012-06-07 20:08:19 +0400 | [diff] [blame] | 2 | * Helpers for using (partial) iovecs. |
Amit Shah | e4d5639 | 2010-04-27 18:04:05 +0530 | [diff] [blame] | 3 | * |
| 4 | * Copyright (C) 2010 Red Hat, Inc. |
| 5 | * |
| 6 | * Author(s): |
| 7 | * Amit Shah <amit.shah@redhat.com> |
Michael Tokarev | 2278a69 | 2012-06-07 20:08:19 +0400 | [diff] [blame] | 8 | * Michael Tokarev <mjt@tls.msk.ru> |
Amit Shah | e4d5639 | 2010-04-27 18:04:05 +0530 | [diff] [blame] | 9 | * |
| 10 | * This work is licensed under the terms of the GNU GPL, version 2. See |
| 11 | * the COPYING file in the top-level directory. |
| 12 | */ |
| 13 | |
| 14 | #include "qemu-common.h" |
| 15 | |
Michael Tokarev | dcf6f5e | 2012-03-11 18:05:12 +0400 | [diff] [blame] | 16 | /** |
| 17 | * count and return data size, in bytes, of an iovec |
| 18 | * starting at `iov' of `iov_cnt' number of elements. |
| 19 | */ |
Hannes Reinecke | 348e7b8 | 2011-07-11 15:02:23 +0200 | [diff] [blame] | 20 | size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt); |
Michael Tokarev | dcf6f5e | 2012-03-11 18:05:12 +0400 | [diff] [blame] | 21 | |
| 22 | /** |
| 23 | * Copy from single continuous buffer to scatter-gather vector of buffers |
| 24 | * (iovec) and back like memcpy() between two continuous memory regions. |
| 25 | * Data in single continuous buffer starting at address `buf' and |
| 26 | * `bytes' bytes long will be copied to/from an iovec `iov' with |
| 27 | * `iov_cnt' number of elements, starting at byte position `offset' |
| 28 | * within the iovec. If the iovec does not contain enough space, |
| 29 | * only part of data will be copied, up to the end of the iovec. |
| 30 | * Number of bytes actually copied will be returned, which is |
| 31 | * min(bytes, iov_size(iov)-offset) |
Michael Tokarev | 2278a69 | 2012-06-07 20:08:19 +0400 | [diff] [blame] | 32 | * `Offset' must point to the inside of iovec. |
| 33 | * It is okay to use very large value for `bytes' since we're |
| 34 | * limited by the size of the iovec anyway, provided that the |
| 35 | * buffer pointed to by buf has enough space. One possible |
| 36 | * such "large" value is -1 (sinice size_t is unsigned), |
| 37 | * so specifying `-1' as `bytes' means 'up to the end of iovec'. |
Michael Tokarev | dcf6f5e | 2012-03-11 18:05:12 +0400 | [diff] [blame] | 38 | */ |
| 39 | size_t iov_from_buf(struct iovec *iov, unsigned int iov_cnt, |
| 40 | size_t offset, const void *buf, size_t bytes); |
| 41 | size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt, |
| 42 | size_t offset, void *buf, size_t bytes); |
| 43 | |
| 44 | /** |
| 45 | * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements, |
| 46 | * starting at byte offset `start', to value `fillc', repeating it |
Michael Tokarev | 2278a69 | 2012-06-07 20:08:19 +0400 | [diff] [blame] | 47 | * `bytes' number of times. `Offset' must point to the inside of iovec. |
Michael Tokarev | dcf6f5e | 2012-03-11 18:05:12 +0400 | [diff] [blame] | 48 | * If `bytes' is large enough, only last bytes portion of iovec, |
| 49 | * up to the end of it, will be filled with the specified value. |
| 50 | * Function return actual number of bytes processed, which is |
| 51 | * min(size, iov_size(iov) - offset). |
Michael Tokarev | 2278a69 | 2012-06-07 20:08:19 +0400 | [diff] [blame] | 52 | * Again, it is okay to use large value for `bytes' to mean "up to the end". |
Michael Tokarev | dcf6f5e | 2012-03-11 18:05:12 +0400 | [diff] [blame] | 53 | */ |
| 54 | size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt, |
| 55 | size_t offset, int fillc, size_t bytes); |
| 56 | |
Michael Tokarev | 3e80bf9 | 2012-03-10 17:00:41 +0400 | [diff] [blame] | 57 | /* |
| 58 | * Send/recv data from/to iovec buffers directly |
| 59 | * |
| 60 | * `offset' bytes in the beginning of iovec buffer are skipped and |
| 61 | * next `bytes' bytes are used, which must be within data of iovec. |
| 62 | * |
Michael Tokarev | 25e5e4c | 2012-03-14 11:18:54 +0400 | [diff] [blame] | 63 | * r = iov_send_recv(sockfd, iov, iovcnt, offset, bytes, true); |
Michael Tokarev | 3e80bf9 | 2012-03-10 17:00:41 +0400 | [diff] [blame] | 64 | * |
| 65 | * is logically equivalent to |
| 66 | * |
| 67 | * char *buf = malloc(bytes); |
| 68 | * iov_to_buf(iov, iovcnt, offset, buf, bytes); |
| 69 | * r = send(sockfd, buf, bytes, 0); |
| 70 | * free(buf); |
Michael Tokarev | 25e5e4c | 2012-03-14 11:18:54 +0400 | [diff] [blame] | 71 | * |
| 72 | * For iov_send_recv() _whole_ area being sent or received |
| 73 | * should be within the iovec, not only beginning of it. |
Michael Tokarev | 3e80bf9 | 2012-03-10 17:00:41 +0400 | [diff] [blame] | 74 | */ |
Michael Tokarev | 25e5e4c | 2012-03-14 11:18:54 +0400 | [diff] [blame] | 75 | ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, |
Michael Tokarev | e3e87df | 2012-03-14 10:56:04 +0400 | [diff] [blame] | 76 | size_t offset, size_t bytes, bool do_send); |
Michael Tokarev | 25e5e4c | 2012-03-14 11:18:54 +0400 | [diff] [blame] | 77 | #define iov_recv(sockfd, iov, iov_cnt, offset, bytes) \ |
| 78 | iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, false) |
| 79 | #define iov_send(sockfd, iov, iov_cnt, offset, bytes) \ |
| 80 | iov_send_recv(sockfd, iov, iov_cnt, offset, bytes, true) |
Michael Tokarev | 3e80bf9 | 2012-03-10 17:00:41 +0400 | [diff] [blame] | 81 | |
Michael Tokarev | dcf6f5e | 2012-03-11 18:05:12 +0400 | [diff] [blame] | 82 | /** |
| 83 | * Produce a text hexdump of iovec `iov' with `iov_cnt' number of elements |
| 84 | * in file `fp', prefixing each line with `prefix' and processing not more |
| 85 | * than `limit' data bytes. |
| 86 | */ |
Gerd Hoffmann | 3a1dca9 | 2011-07-12 13:35:10 +0200 | [diff] [blame] | 87 | void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt, |
| 88 | FILE *fp, const char *prefix, size_t limit); |