aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve Vinoski <[email protected]>2010-09-11 01:41:56 -0400
committerSteve Vinoski <[email protected]>2010-09-11 08:29:25 -0400
commit945bad4712824e534aaa6530304948a4b032f4b0 (patch)
tree60a3c2b3f80c86396c835531ef5859eb20526028
parentf86c89a90a228eed9a58632cc0fb3372b210ec1a (diff)
downloadotp-945bad4712824e534aaa6530304948a4b032f4b0.tar.gz
otp-945bad4712824e534aaa6530304948a4b032f4b0.tar.bz2
otp-945bad4712824e534aaa6530304948a4b032f4b0.zip
fix incorrect writev iovec buffer handling in ei
For platforms that support writev, ei uses iovec structures to be able to easily send noncontiguous data buffers. When sending large messages, the socket can of course block, in which case ei adjusts its iovecs to pick up where it left off when the socket becomes writeable again. Unfortunately the code that handled the case when the number of bytes written are less than the current iovec size adjusted only the iovec byte count but not the iovec data pointer, resulting in the same data being sent multiple times. The fix is trivial: in addition to subtracting the count of bytes already written from the current iovec's size, also increment the current iovec's data pointer by the number of bytes already written. Tested manually on Linux and verified to fix a problem detected in production with writing large binaries from a cnode to a regular node. No unit tests were added, however, because they use the local loopback which acts more like a pipe than an inter-host TCP connection. The closing of the TCP window on the receiving side and the resultant write blocking on the socket, which in turn caused the code that mishandled the iovecs to be exercised, could unfortunately not be readily duplicated in the erl_interface test suite.
-rw-r--r--lib/erl_interface/src/misc/ei_portio.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/lib/erl_interface/src/misc/ei_portio.c b/lib/erl_interface/src/misc/ei_portio.c
index b73ebebbe1..c4e397f1e0 100644
--- a/lib/erl_interface/src/misc/ei_portio.c
+++ b/lib/erl_interface/src/misc/ei_portio.c
@@ -171,6 +171,8 @@ int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned
}
while (i > 0) {
if (i < current_iov[0].iov_len) {
+ char *p = (char*)current_iov[0].iov_base;
+ current_iov[0].iov_base = p + i;
current_iov[0].iov_len -= i;
i = 0;
} else {