1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-07-30 14:43:05 +03:00

Use iovec instead of IOBuf in QuicAsyncUDPSocket::write and QuicAsyncUDPSocket::writeGSO

Summary: See title

Reviewed By: mjoras

Differential Revision: D61048705

fbshipit-source-id: 60dc63cc67f63be6f0ac6cbe0e766172a8c79d7c
This commit is contained in:
Aman Sharma
2024-10-02 15:13:23 -07:00
committed by Facebook GitHub Bot
parent 924183d2d3
commit 2369ecb69b
27 changed files with 626 additions and 454 deletions

View File

@ -69,6 +69,12 @@ constexpr uint16_t kDefaultMsgSizeBackOffSize = 50;
// larger than this, unless configured otherwise.
constexpr uint16_t kDefaultUDPReadBufferSize = 1500;
// UDP's typical MTU size is 1500, so a large number of buffers
// does not make sense. We can optimize for buffer chains with
// fewer than 16 buffers, which is the highest I can think of
// for a real use case.
constexpr size_t kNumIovecBufferChains = 16;
// Number of GRO buffers to use
// 1 means GRO is not enabled
// 64 is the max possible value

View File

@ -32,7 +32,9 @@ bool SinglePacketBatchWriter::append(
ssize_t SinglePacketBatchWriter::write(
QuicAsyncUDPSocket& sock,
const folly::SocketAddress& address) {
return sock.write(address, buf_);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(buf_, vec);
return sock.write(address, vec, iovec_len);
}
// SinglePacketInplaceBatchWriter
@ -54,7 +56,10 @@ ssize_t SinglePacketInplaceBatchWriter::write(
const folly::SocketAddress& address) {
auto& buf = conn_.bufAccessor->buf();
CHECK(!conn_.bufAccessor->isChained());
auto ret = sock.write(address, buf);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(buf, vec);
auto ret = sock.write(address, vec, iovec_len);
conn_.bufAccessor->clear();
return ret;
}
@ -102,7 +107,9 @@ bool SinglePacketBackpressureBatchWriter::append(
ssize_t SinglePacketBackpressureBatchWriter::write(
QuicAsyncUDPSocket& sock,
const folly::SocketAddress& address) {
auto written = sock.write(address, buf_);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(buf_, vec);
auto written = sock.write(address, vec, iovec_len);
lastWriteSuccessful_ = written > 0;
return written;
}
@ -149,7 +156,9 @@ ssize_t SendmmsgPacketBatchWriter::write(
const folly::SocketAddress& address) {
CHECK_GT(bufs_.size(), 0);
if (bufs_.size() == 1) {
return sock.write(address, bufs_[0]);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(bufs_.at(0), vec);
return sock.write(address, vec, iovec_len);
}
int ret = sock.writem(

View File

@ -78,7 +78,9 @@ ssize_t GSOPacketBatchWriter::write(
auto options =
QuicAsyncUDPSocket::WriteOptions(gsoVal, false /*zerocopyVal*/);
options.txTime = txTime_;
return sock.writeGSO(address, buf_, options);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(buf_, vec);
return sock.writeGSO(address, vec, iovec_len, options);
}
GSOInplacePacketBatchWriter::GSOInplacePacketBatchWriter(
@ -159,7 +161,9 @@ ssize_t GSOInplacePacketBatchWriter::write(
auto options =
QuicAsyncUDPSocket::WriteOptions(gsoVal, false /*zerocopyVal*/);
options.txTime = txTime_;
auto bytesWritten = sock.writeGSO(address, buf, options);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(buf, vec);
auto bytesWritten = sock.writeGSO(address, vec, iovec_len, options);
/**
* If there is one more bytes after lastPacketEnd_, that means there is a
* packet we choose not to write in this batch (e.g., it has a size larger
@ -281,8 +285,11 @@ ssize_t SendmmsgGSOPacketBatchWriter::write(
const folly::SocketAddress& /*unused*/) {
CHECK_GT(bufs_.size(), 0);
if (bufs_.size() == 1) {
return (currBufs_ > 1) ? sock.writeGSO(addrs_[0], bufs_[0], options_[0])
: sock.write(addrs_[0], bufs_[0]);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(bufs_[0], vec);
return (currBufs_ > 1)
? sock.writeGSO(addrs_[0], vec, iovec_len, options_[0])
: sock.write(addrs_[0], vec, iovec_len);
}
int ret = sock.writemGSO(

View File

@ -1319,7 +1319,9 @@ void writeCloseCommon(
// best effort writing to the socket, ignore any errors.
Buf packetBufPtr = packetBuf.clone();
auto ret = sock.write(connection.peerAddress, packetBufPtr);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(packetBufPtr, vec);
auto ret = sock.write(connection.peerAddress, vec, iovec_len);
connection.lossState.totalBytesSent += packetSize;
if (ret < 0) {
VLOG(4) << "Error writing connection close " << folly::errnoStr(errno)

View File

@ -159,6 +159,7 @@ cpp_unittest(
deps = [
"//quic/api:quic_batch_writer",
"//quic/common/events:folly_eventbase",
"//quic/common/test:test_utils",
"//quic/common/testutil:mock_async_udp_socket",
"//quic/common/udpsocket:folly_async_udp_socket",
"//quic/fizz/server/handshake:fizz_server_handshake",

View File

@ -77,6 +77,7 @@ quic_add_test(TARGET QuicBatchWriterTest
mvfst_buf_accessor
mvfst_server
mvfst_transport
mvfst_test_utils
)
quic_add_test(TARGET QuicStreamAsyncTransportTest

View File

@ -8,6 +8,7 @@
#include <quic/api/QuicBatchWriter.h>
#include <quic/api/QuicBatchWriterFactory.h>
#include <quic/common/events/FollyQuicEventBase.h>
#include <quic/common/test/TestUtils.h>
#include <quic/common/udpsocket/FollyQuicAsyncUDPSocket.h>
#include <gtest/gtest.h>
@ -464,12 +465,13 @@ TEST_F(QuicBatchWriterTest, InplaceWriterWriteAll) {
ASSERT_TRUE(
batchWriter->append(nullptr, 700, folly::SocketAddress(), nullptr));
EXPECT_CALL(sock, writeGSO(_, _, _))
EXPECT_CALL(sock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t,
QuicAsyncUDPSocket::WriteOptions options) {
EXPECT_EQ(1000 * 5 + 700, buf->length());
EXPECT_EQ(1000 * 5 + 700, vec[0].iov_len);
EXPECT_EQ(1000, options.gso);
return 1000 * 5 + 700;
}));
@ -506,12 +508,11 @@ TEST_F(QuicBatchWriterTest, InplaceWriterWriteOne) {
ASSERT_FALSE(
batchWriter->append(nullptr, 1000, folly::SocketAddress(), nullptr));
EXPECT_CALL(sock, writeGSO(_, _, _))
EXPECT_CALL(sock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf,
auto) {
EXPECT_EQ(1000, buf->length());
.WillOnce(Invoke(
[&](const auto& /* addr */, const struct iovec* vec, size_t, auto) {
EXPECT_EQ(1000, vec[0].iov_len);
return 1000;
}));
EXPECT_EQ(1000, batchWriter->write(sock, folly::SocketAddress()));
@ -550,12 +551,13 @@ TEST_F(QuicBatchWriterTest, InplaceWriterLastOneTooBig) {
bufAccessor->release(std::move(buf));
EXPECT_TRUE(batchWriter->needsFlush(1000));
EXPECT_CALL(sock, writeGSO(_, _, _))
EXPECT_CALL(sock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t,
QuicAsyncUDPSocket::WriteOptions options) {
EXPECT_EQ(5 * 700, buf->length());
EXPECT_EQ(5 * 700, vec[0].iov_len);
EXPECT_EQ(700, options.gso);
return 700 * 5;
}));
@ -598,12 +600,11 @@ TEST_F(QuicBatchWriterTest, InplaceWriterBufResidueCheck) {
rawBuf->append(packetSizeBig);
EXPECT_TRUE(batchWriter->needsFlush(packetSizeBig));
EXPECT_CALL(sock, writeGSO(_, _, _))
EXPECT_CALL(sock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf,
auto) {
EXPECT_EQ(700, buf->length());
.WillOnce(Invoke(
[&](const auto& /* addr */, const struct iovec* vec, size_t, auto) {
EXPECT_EQ(700, vec[0].iov_len);
return 700;
}));
// No crash:
@ -751,11 +752,11 @@ TEST_F(SinglePacketInplaceBatchWriterTest, TestWrite) {
std::shared_ptr<FollyQuicEventBase> qEvb =
std::make_shared<FollyQuicEventBase>(&evb);
quic::test::MockAsyncUDPSocket sock(qEvb);
EXPECT_CALL(sock, write(_, _))
EXPECT_CALL(sock, write(_, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf) {
EXPECT_EQ(appendSize, buf->length());
.WillOnce(
Invoke([&](const auto& /* addr */, const struct iovec* vec, size_t) {
EXPECT_EQ(appendSize, vec[0].iov_len);
return appendSize;
}));
EXPECT_EQ(appendSize, batchWriter->write(sock, folly::SocketAddress()));
@ -822,10 +823,11 @@ TEST_F(SinglePacketBackpressureBatchWriterTest, TestFailedWriteCachedOnEAGAIN) {
folly::SocketAddress(),
&sock_));
EXPECT_CALL(sock_, write(_, _))
EXPECT_CALL(sock_, write(_, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& /*buf*/) {
const struct iovec* /* vec */,
size_t /* iovec_len */) {
errno = EAGAIN;
return 0;
}));
@ -846,11 +848,12 @@ TEST_F(SinglePacketBackpressureBatchWriterTest, TestFailedWriteCachedOnEAGAIN) {
EXPECT_FALSE(conn_.pendingWriteBatch_.buf);
// The write succeeds
EXPECT_CALL(sock_, write(_, _))
EXPECT_CALL(sock_, write(_, _, _))
.Times(1)
.WillOnce(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf) {
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
return ::quic::test::getTotalIovecLen(vec, iovec_len);
}));
EXPECT_EQ(
batchWriter->write(sock_, folly::SocketAddress()), testString.size());

View File

@ -1718,7 +1718,7 @@ TEST_P(QuicTransportImplTestBase, ReadDataAlsoChecksLossAlarm) {
TEST_P(QuicTransportImplTestBase, ConnectionErrorOnWrite) {
transport->transportConn->oneRttWriteCipher = test::createNoOpAead();
auto stream = transport->createBidirectionalStream().value();
EXPECT_CALL(*socketPtr, write(_, _))
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillOnce(SetErrnoAndReturn(ENETUNREACH, -1));
transport->writeChain(stream, folly::IOBuf::copyBuffer("Hey"), true, nullptr);
transport->addDataToStream(
@ -1743,7 +1743,9 @@ TEST_P(QuicTransportImplTestBase, ReadErrorUnsanitizedErrorMsg) {
EXPECT_EQ("You need to calm down.", error.message);
}));
EXPECT_CALL(*socketPtr, write(_, _)).WillOnce(Invoke([](auto&, auto&) {
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillOnce(
Invoke([](const folly::SocketAddress&, const struct iovec*, size_t) {
throw std::runtime_error("You need to calm down.");
return 0;
}));
@ -1765,7 +1767,9 @@ TEST_P(QuicTransportImplTestBase, ConnectionErrorUnhandledException) {
onConnectionSetupError(QuicError(
QuicErrorCode(TransportErrorCode::INTERNAL_ERROR),
std::string("Well there's your problem"))));
EXPECT_CALL(*socketPtr, write(_, _)).WillOnce(Invoke([](auto&, auto&) {
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillOnce(
Invoke([](const folly::SocketAddress&, const struct iovec*, size_t) {
throw std::runtime_error("Well there's your problem");
return 0;
}));
@ -2939,7 +2943,7 @@ TEST_P(QuicTransportImplTestBase, TestGracefulCloseWithActiveStream) {
transport->notifyPendingWriteOnConnection(&wcbConn);
transport->notifyPendingWriteOnStream(stream, &wcb);
transport->setReadCallback(stream, &rcb);
EXPECT_CALL(*socketPtr, write(_, _))
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillRepeatedly(SetErrnoAndReturn(EAGAIN, -1));
transport->writeChain(stream, IOBuf::copyBuffer("hello"), true, &deliveryCb);
EXPECT_CALL(txCb, onByteEventRegistered(getTxMatcher(stream, 0)));
@ -2993,7 +2997,7 @@ TEST_P(QuicTransportImplTestBase, TestGracefulCloseWithNoActiveStream) {
EXPECT_CALL(connCallback, onConnectionError(_)).Times(0);
transport->setReadCallback(stream, &rcb);
EXPECT_CALL(*socketPtr, write(_, _))
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillRepeatedly(SetErrnoAndReturn(EAGAIN, -1));
transport->writeChain(stream, IOBuf::copyBuffer("hello"), true, &deliveryCb);
EXPECT_CALL(txCb, onByteEventRegistered(getTxMatcher(stream, 0)));
@ -3055,7 +3059,7 @@ TEST_P(QuicTransportImplTestBase, TestImmediateClose) {
transport->notifyPendingWriteOnStream(stream, &wcb);
transport->setReadCallback(stream, &rcb);
transport->setPeekCallback(stream, &pcb);
EXPECT_CALL(*socketPtr, write(_, _))
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillRepeatedly(SetErrnoAndReturn(EAGAIN, -1));
transport->writeChain(stream, IOBuf::copyBuffer("hello"), true, &deliveryCb);
EXPECT_CALL(txCb, onByteEventRegistered(getTxMatcher(stream, 0)));
@ -3195,7 +3199,8 @@ TEST_P(QuicTransportImplTestBase, ExceptionInWriteLooperDoesNotCrash) {
transport->writeChain(stream, IOBuf::copyBuffer("hello"), true, nullptr);
transport->addDataToStream(
stream, StreamBuffer(IOBuf::copyBuffer("hello"), 0, false));
EXPECT_CALL(*socketPtr, write(_, _)).WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(*socketPtr, write(_, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(connSetupCallback, onConnectionSetupError(_))
.WillOnce(Invoke([&](auto) { transport.reset(); }));
transport->writeLooper()->runLoopCallback();
@ -4913,11 +4918,11 @@ TEST_P(
}));
// Fail the first write loop.
EXPECT_CALL(*socketPtr, write(_, _))
EXPECT_CALL(*socketPtr, write(_, _, _))
.Times(2) // We attempt to flush the batch twice inside the write loop.
// Fail both.
.WillRepeatedly(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& /*buf*/) {
.WillRepeatedly(
Invoke([&](const folly::SocketAddress&, const struct iovec*, size_t) {
errno = EAGAIN;
return 0;
}));
@ -4937,12 +4942,13 @@ TEST_P(
EXPECT_TRUE(writeCallbackArmed);
// Reset will make one write attempt. We don't care what happens to it
EXPECT_CALL(*socketPtr, write(_, _))
EXPECT_CALL(*socketPtr, write(_, _, _))
.Times(1)
.WillRepeatedly(Invoke([&](const auto& /* addr */,
const std::unique_ptr<folly::IOBuf>& buf) {
.WillRepeatedly(Invoke([&](const folly::SocketAddress&,
const struct iovec* vec,
size_t iovec_len) {
errno = 0;
return buf->computeChainDataLength();
return getTotalIovecLen(vec, iovec_len);
}));
transport.reset();
}

View File

@ -2620,12 +2620,13 @@ TEST_F(QuicTransportFunctionsTest, WriteQuicDataToSocketWithCC) {
EXPECT_CALL(*rawCongestionController, getWritableBytes())
.WillRepeatedly(
InvokeWithoutArgs([&writableBytes]() { return writableBytes; }));
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
EXPECT_LE(iobuf->computeChainDataLength(), 30);
writableBytes -= iobuf->computeChainDataLength();
return iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
size_t totalLen = getTotalIovecLen(vec, iovec_len);
EXPECT_LE(totalLen, 30);
writableBytes -= totalLen;
return totalLen;
}));
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(1);
EXPECT_CALL(*quicStats_, onWrite(_));
@ -2697,7 +2698,7 @@ TEST_F(QuicTransportFunctionsTest, WriteQuicDataToSocketLimitTest) {
// Limit to zero
conn->transportSettings.writeConnectionDataPacketsLimit = 0;
EXPECT_CALL(*rawSocket, write(_, _)).Times(0);
EXPECT_CALL(*rawSocket, write(_, _, _)).Times(0);
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(0);
EXPECT_CALL(*quicStats_, onWrite(_)).Times(0);
auto res = writeQuicDataToSocket(
@ -2720,13 +2721,13 @@ TEST_F(QuicTransportFunctionsTest, WriteQuicDataToSocketLimitTest) {
conn->transportSettings.writeConnectionDataPacketsLimit =
kDefaultWriteConnectionDataPacketLimit;
uint64_t actualWritten = 0;
EXPECT_CALL(*rawSocket, write(_, _))
EXPECT_CALL(*rawSocket, write(_, _, _))
.Times(1)
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
writableBytes -= iobuf->computeChainDataLength();
actualWritten += iobuf->computeChainDataLength();
return iobuf->computeChainDataLength();
.WillOnce(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
writableBytes -= getTotalIovecLen(vec, iovec_len);
actualWritten += getTotalIovecLen(vec, iovec_len);
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(1);
EXPECT_CALL(*quicStats_, onWrite(_)).Times(1);
@ -2754,12 +2755,12 @@ TEST_F(QuicTransportFunctionsTest, WriteQuicDataToSocketLimitTest) {
EXPECT_CALL(*rawCongestionController, getWritableBytes())
.WillRepeatedly(
InvokeWithoutArgs([&writableBytes]() { return writableBytes; }));
EXPECT_CALL(*rawSocket, write(_, _))
EXPECT_CALL(*rawSocket, write(_, _, _))
.Times(kDefaultWriteConnectionDataPacketLimit * 2)
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
actualWritten += iobuf->computeChainDataLength();
return iobuf->computeChainDataLength();
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
actualWritten += getTotalIovecLen(vec, iovec_len);
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*rawCongestionController, onPacketSent(_))
.Times(kDefaultWriteConnectionDataPacketLimit * 2);
@ -2807,14 +2808,14 @@ TEST_F(
EXPECT_CALL(*rawCongestionController, getWritableBytes())
.WillRepeatedly(
InvokeWithoutArgs([&writableBytes]() { return writableBytes; }));
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
EXPECT_LE(
iobuf->computeChainDataLength(),
getTotalIovecLen(vec, iovec_len),
*conn->writableBytesLimit - conn->lossState.totalBytesSent);
writableBytes -= iobuf->computeChainDataLength();
return iobuf->computeChainDataLength();
writableBytes -= getTotalIovecLen(vec, iovec_len);
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_NE(WriteDataReason::NO_WRITE, shouldWriteData(*conn));
writeQuicDataToSocket(
@ -2962,10 +2963,10 @@ TEST_F(QuicTransportFunctionsTest, WriteBlockedFrameWhenBlocked) {
auto originalNextSeq = conn->ackStates.appDataAckState.nextPacketNum;
uint64_t sentBytes = 0;
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
auto len = iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
auto len = getTotalIovecLen(vec, iovec_len);
sentBytes += len;
return len;
}));
@ -3033,10 +3034,10 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingNewData) {
auto currentStreamWriteOffset = stream1->currentWriteOffset;
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(1);
EXPECT_CALL(*rawSocket, write(_, _))
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
auto len = iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillOnce(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
auto len = getTotalIovecLen(vec, iovec_len);
EXPECT_EQ(conn->udpSendPacketLen - aead->getCipherOverhead(), len);
return len;
}));
@ -3061,7 +3062,7 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingOldData) {
auto socket =
std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = socket.get();
EXPECT_CALL(*rawSocket, write(_, _)).WillRepeatedly(Return(100));
EXPECT_CALL(*rawSocket, write(_, _, _)).WillRepeatedly(Return(100));
auto capturingAead = std::make_unique<MockAead>();
auto stream = conn->streamManager->createNextBidirectionalStream().value();
auto buf = folly::IOBuf::copyBuffer("Where you wanna go");
@ -3111,7 +3112,7 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingOldDataAckFreq) {
auto socket =
std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = socket.get();
EXPECT_CALL(*rawSocket, write(_, _)).WillRepeatedly(Return(100));
EXPECT_CALL(*rawSocket, write(_, _, _)).WillRepeatedly(Return(100));
auto capturingAead = std::make_unique<MockAead>();
auto stream = conn->streamManager->createNextBidirectionalStream().value();
auto buf = folly::IOBuf::copyBuffer("Where you wanna go");
@ -3186,10 +3187,10 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingCryptoData) {
auto currentStreamWriteOffset = cryptoStream->currentWriteOffset;
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(1);
EXPECT_CALL(*rawSocket, write(_, _))
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
auto len = iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillOnce(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
auto len = getTotalIovecLen(vec, iovec_len);
EXPECT_EQ(conn.udpSendPacketLen - aead->getCipherOverhead(), len);
return len;
}));
@ -3234,10 +3235,10 @@ TEST_F(QuicTransportFunctionsTest, WriteableBytesLimitedProbingCryptoData) {
auto currentStreamWriteOffset = cryptoStream->currentWriteOffset;
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(2);
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
auto len = iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
auto len = getTotalIovecLen(vec, iovec_len);
EXPECT_EQ(conn.udpSendPacketLen - aead->getCipherOverhead(), len);
return len;
}));
@ -3265,7 +3266,7 @@ TEST_F(QuicTransportFunctionsTest, ProbingNotFallbackToPingWhenNoQuota) {
std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = socket.get();
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(0);
EXPECT_CALL(*rawSocket, write(_, _)).Times(0);
EXPECT_CALL(*rawSocket, write(_, _, _)).Times(0);
uint8_t probesToSend = 0;
EXPECT_EQ(
0,
@ -3286,11 +3287,11 @@ TEST_F(QuicTransportFunctionsTest, ProbingFallbackToPing) {
auto socket =
std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = socket.get();
EXPECT_CALL(*rawSocket, write(_, _))
EXPECT_CALL(*rawSocket, write(_, _, _))
.Times(1)
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
return iobuf->computeChainDataLength();
.WillOnce(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
return getTotalIovecLen(vec, iovec_len);
}));
uint8_t probesToSend = 1;
EXPECT_EQ(
@ -3315,11 +3316,11 @@ TEST_F(QuicTransportFunctionsTest, ProbingFallbackToImmediateAck) {
auto socket =
std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = socket.get();
EXPECT_CALL(*rawSocket, write(_, _))
EXPECT_CALL(*rawSocket, write(_, _, _))
.Times(1)
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
return iobuf->computeChainDataLength();
.WillOnce(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
return getTotalIovecLen(vec, iovec_len);
}));
uint8_t probesToSend = 1;
EXPECT_EQ(
@ -3464,12 +3465,12 @@ TEST_F(QuicTransportFunctionsTest, WritePureAckWhenNoWritableBytes) {
.WillRepeatedly(Return(0));
uint64_t actualWritten = 0;
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
EXPECT_LE(iobuf->computeChainDataLength(), 30);
actualWritten += iobuf->computeChainDataLength();
return iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
EXPECT_LE(getTotalIovecLen(vec, iovec_len), 30);
actualWritten += getTotalIovecLen(vec, iovec_len);
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*rawCongestionController, onPacketSent(_)).Times(0);
auto res = writeQuicDataToSocket(
@ -4051,11 +4052,11 @@ TEST_F(QuicTransportFunctionsTest, WriteLimitBytRttFraction) {
writeDataToQuicStream(*stream1, buf->clone(), true);
uint64_t actualWritten = 0;
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
actualWritten += iobuf->computeChainDataLength();
return iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
actualWritten += getTotalIovecLen(vec, iovec_len);
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*rawCongestionController, getWritableBytes())
.WillRepeatedly(Return(50));
@ -4111,7 +4112,7 @@ TEST_F(QuicTransportFunctionsTest, WriteLimitBytRttFractionNoLimit) {
auto buf = buildRandomInputData(2048 * 2048);
writeDataToQuicStream(*stream1, buf->clone(), true);
EXPECT_CALL(*rawSocket, write(_, _)).WillRepeatedly(Return(1));
EXPECT_CALL(*rawSocket, write(_, _, _)).WillRepeatedly(Return(1));
EXPECT_CALL(*rawCongestionController, getWritableBytes())
.WillRepeatedly(Return(50));
auto writeLoopBeginTime = Clock::now();
@ -4248,10 +4249,10 @@ TEST_F(QuicTransportFunctionsTest, ProbeWriteNewFunctionalFrames) {
auto sock = std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = sock.get();
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
return iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
return getTotalIovecLen(vec, iovec_len);
}));
auto stream = conn->streamManager->createNextBidirectionalStream().value();
@ -4299,10 +4300,10 @@ TEST_F(QuicTransportFunctionsTest, ProbeWriteNewFunctionalFramesAckFreq) {
auto sock = std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb);
auto rawSocket = sock.get();
EXPECT_CALL(*rawSocket, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
return iobuf->computeChainDataLength();
EXPECT_CALL(*rawSocket, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
return getTotalIovecLen(vec, iovec_len);
}));
auto stream = conn->streamManager->createNextBidirectionalStream().value();
@ -4362,17 +4363,18 @@ TEST_F(QuicTransportFunctionsTest, WriteWithInplaceBuilder) {
auto stream = conn->streamManager->createNextBidirectionalStream().value();
auto buf = folly::IOBuf::copyBuffer("Andante in C minor");
writeDataToQuicStream(*stream, buf->clone(), true);
EXPECT_CALL(mockSock, writeGSO(_, _, _))
EXPECT_CALL(mockSock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& sockBuf,
const struct iovec* vec,
size_t iovec_len,
auto) {
EXPECT_GT(bufPtr->length(), 0);
EXPECT_GE(sockBuf->length(), buf->length());
EXPECT_EQ(sockBuf.get(), bufPtr);
EXPECT_TRUE(folly::IOBufEqualTo()(*sockBuf, *bufPtr));
EXPECT_FALSE(sockBuf->isChained());
return sockBuf->computeChainDataLength();
EXPECT_GE(vec[0].iov_len, buf->length());
EXPECT_TRUE(folly::IOBufEqualTo()(
*folly::IOBuf::wrapIov(vec, iovec_len), *bufPtr));
EXPECT_EQ(iovec_len, 1);
return getTotalIovecLen(vec, iovec_len);
}));
writeQuicDataToSocket(
mockSock,
@ -4401,7 +4403,7 @@ TEST_F(QuicTransportFunctionsTest, WriteWithInplaceBuilderRollbackBuf) {
std::make_shared<FollyQuicEventBase>(&evb);
quic::test::MockAsyncUDPSocket mockSock(qEvb);
EXPECT_CALL(mockSock, getGSO()).WillRepeatedly(Return(true));
EXPECT_CALL(mockSock, write(_, _)).Times(0);
EXPECT_CALL(mockSock, write(_, _, _)).Times(0);
writeQuicDataToSocket(
mockSock,
*conn,
@ -4432,17 +4434,18 @@ TEST_F(QuicTransportFunctionsTest, WriteWithInplaceBuilderGSOMultiplePackets) {
auto stream = conn->streamManager->createNextBidirectionalStream().value();
auto buf = buildRandomInputData(conn->udpSendPacketLen * 10);
writeDataToQuicStream(*stream, buf->clone(), true);
EXPECT_CALL(mockSock, writeGSO(_, _, _))
EXPECT_CALL(mockSock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& sockBuf,
const struct iovec* vec,
size_t iovec_len,
QuicAsyncUDPSocket::WriteOptions options) {
EXPECT_LE(options.gso, conn->udpSendPacketLen);
EXPECT_GT(bufPtr->length(), 0);
EXPECT_EQ(sockBuf.get(), bufPtr);
EXPECT_TRUE(folly::IOBufEqualTo()(*sockBuf, *bufPtr));
EXPECT_FALSE(sockBuf->isChained());
return sockBuf->length();
EXPECT_GT(vec[0].iov_len, 0);
EXPECT_TRUE(folly::IOBufEqualTo()(
*folly::IOBuf::wrapIov(vec, iovec_len), *bufPtr));
EXPECT_EQ(iovec_len, 1);
return getTotalIovecLen(vec, iovec_len);
}));
writeQuicDataToSocket(
mockSock,
@ -4479,20 +4482,21 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingWithInplaceBuilder) {
conn->udpSendPacketLen *
conn->transportSettings.writeConnectionDataPacketsLimit);
writeDataToQuicStream(*stream, inputBuf->clone(), true);
EXPECT_CALL(mockSock, writeGSO(_, _, _))
EXPECT_CALL(mockSock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& sockBuf,
const struct iovec* vec,
size_t iovec_len,
QuicAsyncUDPSocket::WriteOptions options) {
EXPECT_LE(options.gso, conn->udpSendPacketLen);
EXPECT_GE(
bufPtr->length(),
conn->udpSendPacketLen *
conn->transportSettings.writeConnectionDataPacketsLimit);
EXPECT_EQ(sockBuf.get(), bufPtr);
EXPECT_TRUE(folly::IOBufEqualTo()(*sockBuf, *bufPtr));
EXPECT_FALSE(sockBuf->isChained());
return sockBuf->length();
EXPECT_TRUE(folly::IOBufEqualTo()(
*folly::IOBuf::wrapIov(vec, iovec_len), *bufPtr));
EXPECT_EQ(iovec_len, 1);
return getTotalIovecLen(vec, iovec_len);
}));
writeQuicDataToSocket(
mockSock,
@ -4515,14 +4519,15 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingWithInplaceBuilder) {
conn->outstandings.packets.front().metadata.encodedSize;
auto outstandingPacketsCount = conn->outstandings.packets.size();
ASSERT_EQ(firstPacketSize, conn->udpSendPacketLen);
EXPECT_CALL(mockSock, writeGSO(_, _, _))
EXPECT_CALL(mockSock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t iovec_len,
auto) {
EXPECT_FALSE(buf->isChained());
EXPECT_EQ(buf->length(), firstPacketSize);
return buf->length();
EXPECT_EQ(iovec_len, 1);
EXPECT_EQ(vec[0].iov_len, firstPacketSize);
return getTotalIovecLen(vec, iovec_len);
}));
writeProbingDataToSocketForTest(
mockSock,
@ -4536,15 +4541,16 @@ TEST_F(QuicTransportFunctionsTest, WriteProbingWithInplaceBuilder) {
EXPECT_EQ(0, bufPtr->headroom());
// Clone again, this time 2 pacckets.
EXPECT_CALL(mockSock, writeGSO(_, _, _))
EXPECT_CALL(mockSock, writeGSO(_, _, _, _))
.Times(1)
.WillOnce(Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t iovec_len,
QuicAsyncUDPSocket::WriteOptions options) {
EXPECT_FALSE(buf->isChained());
EXPECT_EQ(iovec_len, 1);
EXPECT_EQ(conn->udpSendPacketLen, options.gso);
EXPECT_EQ(buf->length(), conn->udpSendPacketLen * 2);
return buf->length();
EXPECT_EQ(vec[0].iov_len, conn->udpSendPacketLen * 2);
return getTotalIovecLen(vec, iovec_len);
}));
writeProbingDataToSocketForTest(
mockSock,

View File

@ -142,12 +142,6 @@ RegularQuicWritePacket stripPaddingFrames(RegularQuicWritePacket packet) {
return packet;
}
size_t bufLength(
const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
return buf->computeChainDataLength();
}
void dropPackets(QuicServerConnectionState& conn) {
for (const auto& packet : conn.outstandings.packets) {
for (const auto& frame : packet.packet.frames) {
@ -267,11 +261,11 @@ TEST_F(QuicTransportTest, WriteDataWithProbing) {
Invoke([&](const auto& /* packet */) { onPacketSentCounter++; }));
// Probing will send out one. Then regular write may send out multiple ones:
int socketWriteCounter = 0;
EXPECT_CALL(*socket_, write(_, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& iobuf) {
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWriteCounter++;
return iobuf->computeChainDataLength();
return getTotalIovecLen(vec, iovec_len);
}));
transport_->writeChain(streamId, buf->clone(), true);
loopForWrites();
@ -1630,7 +1624,8 @@ TEST_F(QuicTransportTest, WriteSmall) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
transport_->setStreamPriority(stream, Priority(0, false));
loopForWrites();
@ -1639,7 +1634,8 @@ TEST_F(QuicTransportTest, WriteSmall) {
// Test retransmission
dropPackets(conn);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1661,9 +1657,9 @@ TEST_F(QuicTransportTest, WriteLarge) {
auto buf =
buildRandomInputData(NumFullPackets * kDefaultUDPSendPacketLen + 20);
folly::IOBuf passedIn;
EXPECT_CALL(*socket_, write(_, _))
EXPECT_CALL(*socket_, write(_, _, _))
.Times(NumFullPackets + 1)
.WillRepeatedly(Invoke(bufLength));
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
auto& conn = transport_->getConnectionState();
@ -1672,9 +1668,9 @@ TEST_F(QuicTransportTest, WriteLarge) {
// Test retransmission
dropPackets(conn);
EXPECT_CALL(*socket_, write(_, _))
EXPECT_CALL(*socket_, write(_, _, _))
.Times(NumFullPackets + 1)
.WillRepeatedly(Invoke(bufLength));
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1692,7 +1688,8 @@ TEST_F(QuicTransportTest, WriteLarge) {
TEST_F(QuicTransportTest, WriteMultipleTimes) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
auto& conn = transport_->getConnectionState();
@ -1703,7 +1700,8 @@ TEST_F(QuicTransportTest, WriteMultipleTimes) {
conn.outstandings.reset();
conn.streamManager->findStream(stream)->retransmissionBuffer.clear();
buf = buildRandomInputData(50);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
verifyCorrectness(conn, originalWriteOffset, stream, *buf);
@ -1715,14 +1713,16 @@ TEST_F(QuicTransportTest, WriteMultipleStreams) {
auto s1 = transport_->createBidirectionalStream().value();
auto s2 = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(s1, buf->clone(), false);
loopForWrites();
auto& conn = transport_->getConnectionState();
verifyCorrectness(conn, 0, s1, *buf);
auto buf2 = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(s2, buf2->clone(), false);
loopForWrites();
verifyCorrectness(conn, 0, s2, *buf2);
@ -1730,7 +1730,8 @@ TEST_F(QuicTransportTest, WriteMultipleStreams) {
dropPackets(conn);
// Should retransmit lost streams in a single packet
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1761,7 +1762,8 @@ TEST_F(QuicTransportTest, WriteFlowControl) {
auto buf = buildRandomInputData(150);
folly::IOBuf passedIn;
// Write stream blocked frame
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(streamId, buf->clone(), false);
loopForWrites();
@ -1793,7 +1795,8 @@ TEST_F(QuicTransportTest, WriteFlowControl) {
stream->flowControlState.pendingBlockedFrame = false;
EXPECT_CALL(*mockQLogger, addTransportStateUpdate(getFlowControlEvent(200)));
conn.streamManager->updateWritableStreams(*stream);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1809,7 +1812,9 @@ TEST_F(QuicTransportTest, WriteFlowControl) {
auto num_outstandings = conn.outstandings.packets.size();
stream->flowControlState.peerAdvertisedMaxOffset = 300;
conn.streamManager->updateWritableStreams(*stream);
EXPECT_CALL(*socket_, write(_, _)).Times(2).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.Times(2)
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1841,7 +1846,7 @@ TEST_F(QuicTransportTest, WriteFlowControl) {
// Try again, verify that there should not be any Data blocked frame emitted
// again.
EXPECT_CALL(*socket_, write(_, _)).Times(0);
EXPECT_CALL(*socket_, write(_, _, _)).Times(0);
writeQuicDataToSocket(
*socket_,
conn,
@ -1854,7 +1859,8 @@ TEST_F(QuicTransportTest, WriteFlowControl) {
// Flow control lifted
stream->conn.flowControlState.peerAdvertisedMaxOffset = 300;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1871,7 +1877,7 @@ TEST_F(QuicTransportTest, WriteErrorEagain) {
// Test network error
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(SetErrnoAndReturn(EAGAIN, -1));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(SetErrnoAndReturn(EAGAIN, -1));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
}
@ -1880,7 +1886,7 @@ TEST_F(QuicTransportTest, WriteErrorBad) {
// Test network error
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(SetErrnoAndReturn(EBADF, -1));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
EXPECT_TRUE(transport_->closed);
@ -1898,7 +1904,8 @@ TEST_F(QuicTransportTest, WriteInvalid) {
TEST_F(QuicTransportTest, WriteFin) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), true);
loopForWrites();
auto& conn = transport_->getConnectionState();
@ -1906,7 +1913,8 @@ TEST_F(QuicTransportTest, WriteFin) {
// Test retransmission
dropPackets(conn);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1923,10 +1931,12 @@ TEST_F(QuicTransportTest, WriteFin) {
TEST_F(QuicTransportTest, WriteOnlyFin) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, nullptr, true);
loopForWrites();
auto& conn = transport_->getConnectionState();
@ -1934,7 +1944,8 @@ TEST_F(QuicTransportTest, WriteOnlyFin) {
// Test retransmission
dropPackets(conn);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -1951,7 +1962,8 @@ TEST_F(QuicTransportTest, WriteOnlyFin) {
TEST_F(QuicTransportTest, WriteDataWithRetransmission) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
auto& conn = transport_->getConnectionState();
@ -1959,7 +1971,8 @@ TEST_F(QuicTransportTest, WriteDataWithRetransmission) {
dropPackets(conn);
auto buf2 = buildRandomInputData(50);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf2->clone(), false);
loopForWrites();
// The first packet was lost. We should expect this packet contains both
@ -1975,7 +1988,8 @@ TEST_F(QuicTransportTest, WriteImmediateAcks) {
PacketNum end = 15;
conn.ackStates.appDataAckState.needsToSendAckImmediately = true;
addAckStatesWithCurrentTimestamps(conn.ackStates.appDataAckState, start, end);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -2001,7 +2015,8 @@ TEST_F(QuicTransportTest, WritePendingAckIfHavingData) {
addAckStatesWithCurrentTimestamps(conn.ackStates.appDataAckState, start, end);
conn.ackStates.appDataAckState.needsToSendAckImmediately = false;
conn.ackStates.appDataAckState.numNonRxPacketsRecvd = 3;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
// We should write acks if there is data pending
transport_->writeChain(streamId, buf->clone(), true);
loopForWrites();
@ -2042,7 +2057,8 @@ TEST_F(QuicTransportTest, NoWritePendingAckIfHavingData) {
addAckStatesWithCurrentTimestamps(conn.ackStates.appDataAckState, start, end);
conn.ackStates.appDataAckState.needsToSendAckImmediately = false;
conn.ackStates.appDataAckState.numNonRxPacketsRecvd = 3;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
// We should write acks if there is data pending
transport_->writeChain(streamId, buf->clone(), true);
loopForWrites();
@ -2071,7 +2087,8 @@ TEST_F(QuicTransportTest, NoWritePendingAckIfHavingData) {
TEST_F(QuicTransportTest, RstStream) {
auto streamId = transport_->createBidirectionalStream().value();
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
loopForWrites();
EXPECT_EQ(1, transport_->getConnectionState().outstandings.packets.size());
@ -2107,7 +2124,8 @@ TEST_F(QuicTransportTest, RstStream) {
TEST_F(QuicTransportTest, StopSending) {
auto streamId = transport_->createBidirectionalStream().value();
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->stopSending(streamId, GenericApplicationErrorCode::UNKNOWN);
loopForWrites();
EXPECT_EQ(1, transport_->getConnectionState().outstandings.packets.size());
@ -2136,7 +2154,8 @@ TEST_F(QuicTransportTest, StopSending) {
TEST_F(QuicTransportTest, StopSendingReadCallbackDefault) {
auto streamId = transport_->createBidirectionalStream().value();
NiceMock<MockReadCallback> readCb;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->setReadCallback(streamId, &readCb);
transport_->setReadCallback(streamId, nullptr);
loopForWrites();
@ -2166,7 +2185,8 @@ TEST_F(QuicTransportTest, StopSendingReadCallbackDefault) {
TEST_F(QuicTransportTest, StopSendingReadCallback) {
auto streamId = transport_->createBidirectionalStream().value();
NiceMock<MockReadCallback> readCb;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->setReadCallback(streamId, &readCb);
transport_->setReadCallback(
streamId, nullptr, GenericApplicationErrorCode::UNKNOWN);
@ -2213,7 +2233,8 @@ TEST_F(QuicTransportTest, NoStopSendingReadCallback) {
}
TEST_F(QuicTransportTest, SendPathChallenge) {
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto& conn = transport_->getConnectionState();
PathChallengeFrame pathChallenge(123);
conn.pendingEvents.pathChallenge = pathChallenge;
@ -2257,7 +2278,8 @@ TEST_F(QuicTransportTest, SendPathChallenge) {
}
TEST_F(QuicTransportTest, PathValidationTimeoutExpired) {
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto& conn = transport_->getConnectionState();
PathChallengeFrame pathChallenge(123);
conn.pendingEvents.pathChallenge = pathChallenge;
@ -2442,7 +2464,8 @@ TEST_F(QuicTransportTest, DoNotResendLostPathChallengeIfNotOutstanding) {
}
TEST_F(QuicTransportTest, SendPathResponse) {
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto& conn = transport_->getConnectionState();
EXPECT_EQ(conn.pendingEvents.frames.size(), 0);
PathResponseFrame pathResponse(123);
@ -2565,7 +2588,8 @@ TEST_F(QuicTransportTest, ResendPathResponseOnLoss) {
}
TEST_F(QuicTransportTest, SendNewConnectionIdFrame) {
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto& conn = transport_->getConnectionState();
NewConnectionIdFrame newConnId(
1, 0, ConnectionId({2, 4, 2, 3}), StatelessResetToken());
@ -2656,7 +2680,7 @@ TEST_F(QuicTransportTest, BusyWriteLoopDetection) {
EXPECT_TRUE(conn.writeDebugState.needsWriteLoopDetect);
EXPECT_EQ(0, conn.writeDebugState.currentEmptyLoopCount);
EXPECT_EQ(WriteDataReason::STREAM, conn.writeDebugState.writeDataReason);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Return(1000));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(Return(1000));
loopForWrites();
EXPECT_EQ(1, conn.outstandings.packets.size());
EXPECT_EQ(0, conn.writeDebugState.currentEmptyLoopCount);
@ -2667,7 +2691,7 @@ TEST_F(QuicTransportTest, BusyWriteLoopDetection) {
EXPECT_TRUE(
WriteDataReason::STREAM_WINDOW_UPDATE ==
conn.writeDebugState.writeDataReason);
EXPECT_CALL(*socket_, write(_, _)).Times(0);
EXPECT_CALL(*socket_, write(_, _, _)).Times(0);
EXPECT_CALL(
*rawLoopDetectorCallback,
onSuspiciousWriteLoops(1, WriteDataReason::STREAM_WINDOW_UPDATE, _, _))
@ -2704,7 +2728,8 @@ TEST_F(QuicTransportTest, ResendNewConnectionIdOnLoss) {
}
TEST_F(QuicTransportTest, SendRetireConnectionIdFrame) {
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto& conn = transport_->getConnectionState();
RetireConnectionIdFrame retireConnId(1);
sendSimpleFrame(conn, retireConnId);
@ -2790,7 +2815,8 @@ TEST_F(QuicTransportTest, ResendRetireConnectionIdOnLoss) {
TEST_F(QuicTransportTest, NonWritableStreamAPI) {
auto streamId = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto& conn = transport_->getConnectionState();
auto streamState = conn.streamManager->getStream(streamId);
@ -2826,7 +2852,8 @@ TEST_F(QuicTransportTest, RstWrittenStream) {
ASSERT_TRUE(stream);
auto currentWriteOffset = stream->currentWriteOffset;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
loopForWrites();
// 2 packets are outstanding: one for Stream frame one for RstStream frame:
@ -2860,7 +2887,7 @@ TEST_F(QuicTransportTest, RstWrittenStream) {
TEST_F(QuicTransportTest, RstStreamUDPWriteFailNonFatal) {
auto streamId = transport_->createBidirectionalStream().value();
EXPECT_CALL(*socket_, write(_, _)).WillOnce(SetErrnoAndReturn(EAGAIN, -1));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(SetErrnoAndReturn(EAGAIN, -1));
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
loopForWrites();
@ -2897,7 +2924,7 @@ TEST_F(QuicTransportTest, RstStreamUDPWriteFailNonFatal) {
TEST_F(QuicTransportTest, RstStreamUDPWriteFailFatal) {
auto streamId = transport_->createBidirectionalStream().value();
EXPECT_CALL(*socket_, write(_, _))
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(SetErrnoAndReturn(EBADF, -1));
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
loopForWrites();
@ -2916,7 +2943,8 @@ TEST_F(QuicTransportTest, WriteAfterSendRst) {
auto stream = conn.streamManager->findStream(streamId);
ASSERT_TRUE(stream);
auto currentWriteOffset = stream->currentWriteOffset;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN);
loopForWrites();
@ -2960,7 +2988,8 @@ TEST_F(QuicTransportTest, WriteAfterSendRst) {
TEST_F(QuicTransportTest, DoubleReset) {
auto streamId = transport_->createBidirectionalStream().value();
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
EXPECT_FALSE(
transport_->resetStream(streamId, GenericApplicationErrorCode::UNKNOWN)
.hasError());
@ -2975,7 +3004,8 @@ TEST_F(QuicTransportTest, DoubleReset) {
TEST_F(QuicTransportTest, WriteStreamDataSetLossAlarm) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(1);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
EXPECT_TRUE(transport_->isLossTimeoutScheduled());
@ -2986,7 +3016,8 @@ TEST_F(QuicTransportTest, WriteAckNotSetLossAlarm) {
addAckStatesWithCurrentTimestamps(
conn.ackStates.appDataAckState, 0 /* start */, 100 /* ind */);
conn.ackStates.appDataAckState.needsToSendAckImmediately = true;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto res = writeQuicDataToSocket(
*socket_,
conn,
@ -3005,7 +3036,8 @@ TEST_F(QuicTransportTest, WriteWindowUpdate) {
conn.flowControlState.windowSize = 100;
conn.flowControlState.advertisedMaxOffset = 0;
conn.pendingEvents.connWindowUpdate = true;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
auto res = writeQuicDataToSocket(
*socket_,
conn,
@ -3041,7 +3073,8 @@ TEST_F(QuicTransportTest, WriteWindowUpdate) {
streamState->flowControlState.advertisedMaxOffset = 0;
MaxStreamDataFrame frame(stream, 100);
conn.streamManager->queueWindowUpdate(stream);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
res = writeQuicDataToSocket(
*socket_,
conn,
@ -3084,7 +3117,8 @@ TEST_F(QuicTransportTest, DeliveryCallbackClosesClosedTransport) {
auto stream1 = transport_->createBidirectionalStream().value();
auto buf1 = buildRandomInputData(20);
TransportClosingDeliveryCallback dc(transport_.get(), 20);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream1, buf1->clone(), true, &dc);
loopForWrites();
transport_->close(none);
@ -3094,7 +3128,8 @@ TEST_F(QuicTransportTest, DeliveryCallbackClosesTransportOnDelivered) {
auto stream1 = transport_->createBidirectionalStream().value();
auto buf1 = buildRandomInputData(20);
TransportClosingDeliveryCallback dc(transport_.get(), 0);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->registerDeliveryCallback(stream1, 0, &dc);
transport_->writeChain(stream1, buf1->clone(), true);
loopForWrites();
@ -3113,7 +3148,8 @@ TEST_F(QuicTransportTest, InvokeDeliveryCallbacksNothingDelivered) {
NiceMock<MockDeliveryCallback> mockedDeliveryCallback;
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->registerDeliveryCallback(stream, 1, &mockedDeliveryCallback);
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
@ -3147,7 +3183,8 @@ TEST_F(QuicTransportTest, InvokeDeliveryCallbacksAllDelivered) {
NiceMock<MockDeliveryCallback> mockedDeliveryCallback;
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(20);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->registerDeliveryCallback(stream, 1, &mockedDeliveryCallback);
transport_->writeChain(stream, buf->clone(), true);
loopForWrites();
@ -3171,7 +3208,8 @@ TEST_F(QuicTransportTest, InvokeDeliveryCallbacksPartialDelivered) {
mockedDeliveryCallback2;
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(100);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->registerDeliveryCallback(stream, 50, &mockedDeliveryCallback1);
transport_->registerDeliveryCallback(stream, 150, &mockedDeliveryCallback2);
transport_->writeChain(stream, buf->clone(), false);
@ -3212,7 +3250,8 @@ TEST_F(QuicTransportTest, InvokeDeliveryCallbacksRetxBuffer) {
mockedDeliveryCallback2;
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(100);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->registerDeliveryCallback(stream, 50, &mockedDeliveryCallback1);
transport_->registerDeliveryCallback(stream, 150, &mockedDeliveryCallback2);
transport_->writeChain(stream, buf->clone(), false);
@ -3259,7 +3298,8 @@ TEST_F(QuicTransportTest, InvokeDeliveryCallbacksLossAndRetxBuffer) {
mockedDeliveryCallback2, mockedDeliveryCallback3;
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(100);
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->registerDeliveryCallback(stream, 30, &mockedDeliveryCallback1);
transport_->registerDeliveryCallback(stream, 50, &mockedDeliveryCallback2);
transport_->registerDeliveryCallback(stream, 150, &mockedDeliveryCallback3);
@ -4219,7 +4259,8 @@ TEST_F(QuicTransportTest, WriteStreamFromMiddleOfMap) {
auto stream2 = conn.streamManager->getStream(s2);
writeDataToQuicStream(*stream2, buf2->clone(), false);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -4242,7 +4283,8 @@ TEST_F(QuicTransportTest, WriteStreamFromMiddleOfMap) {
conn.streamManager->writeQueue().setNextScheduledStream(s2);
writableBytes = kDefaultUDPSendPacketLen - 100;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -4266,7 +4308,8 @@ TEST_F(QuicTransportTest, WriteStreamFromMiddleOfMap) {
// Test wrap around
conn.streamManager->writeQueue().setNextScheduledStream(s2);
writableBytes = kDefaultUDPSendPacketLen;
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillOnce(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
writeQuicDataToSocket(
*socket_,
conn,
@ -4392,7 +4435,8 @@ TEST_F(QuicTransportTest, CloseTransportCancelsAckTimeout) {
auto stream = transport_->createBidirectionalStream().value();
auto buf = buildRandomInputData(kDefaultUDPSendPacketLen + 20);
folly::IOBuf passedIn;
EXPECT_CALL(*socket_, write(_, _)).WillRepeatedly(Invoke(bufLength));
EXPECT_CALL(*socket_, write(_, _, _))
.WillRepeatedly(testing::WithArgs<1, 2>(Invoke(getTotalIovecLen)));
transport_->writeChain(stream, buf->clone(), false);
loopForWrites();
transport_->scheduleLossTimeout(500ms);
@ -4453,7 +4497,7 @@ TEST_F(QuicTransportTest, PacedWriteNoDataToWrite) {
ASSERT_EQ(
WriteDataReason::NO_WRITE,
shouldWriteData(transport_->getConnectionState()));
EXPECT_CALL(*socket_, write(_, _)).Times(0);
EXPECT_CALL(*socket_, write(_, _, _)).Times(0);
transport_->pacedWrite();
}
@ -4474,7 +4518,7 @@ TEST_F(QuicTransportTest, PacingWillBurstFirst) {
auto buf = buildRandomInputData(200);
auto streamId = transport_->createBidirectionalStream().value();
transport_->writeChain(streamId, buf->clone(), false);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Return(0));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(Return(0));
EXPECT_CALL(*rawPacer, updateAndGetWriteBatchSize(_))
.WillRepeatedly(Return(1));
transport_->pacedWrite();
@ -4499,7 +4543,7 @@ TEST_F(QuicTransportTest, AlreadyScheduledPacingNoWrite) {
auto buf = buildRandomInputData(200);
auto streamId = transport_->createBidirectionalStream().value();
transport_->writeChain(streamId, buf->clone(), false);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Return(0));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(Return(0));
EXPECT_CALL(*rawPacer, updateAndGetWriteBatchSize(_))
.WillRepeatedly(Return(1));
EXPECT_CALL(*rawPacer, getTimeUntilNextWrite(_))
@ -4510,7 +4554,7 @@ TEST_F(QuicTransportTest, AlreadyScheduledPacingNoWrite) {
ASSERT_NE(WriteDataReason::NO_WRITE, shouldWriteData(conn));
EXPECT_TRUE(transport_->isPacingScheduled());
EXPECT_CALL(*socket_, write(_, _)).Times(0);
EXPECT_CALL(*socket_, write(_, _, _)).Times(0);
transport_->pacedWrite();
}
@ -4531,7 +4575,7 @@ TEST_F(QuicTransportTest, NoScheduleIfNoNewData) {
auto buf = buildRandomInputData(200);
auto streamId = transport_->createBidirectionalStream().value();
transport_->writeChain(streamId, buf->clone(), false);
EXPECT_CALL(*socket_, write(_, _)).WillOnce(Return(0));
EXPECT_CALL(*socket_, write(_, _, _)).WillOnce(Return(0));
EXPECT_CALL(*rawPacer, updateAndGetWriteBatchSize(_))
.WillRepeatedly(Return(1));
// This will write out everything. After that because there is no new data,

View File

@ -1041,9 +1041,11 @@ void QuicClientTransport::startCryptoHandshake() {
conn_->transportParametersEncoded = true;
if (!conn_->transportSettings.flowPriming.empty() &&
conn_->peerAddress.isInitialized()) {
socket_->write(
conn_->peerAddress,
folly::IOBuf::copyBuffer(conn_->transportSettings.flowPriming));
auto flowPrimingBuf =
folly::IOBuf::copyBuffer(conn_->transportSettings.flowPriming);
iovec vec[kNumIovecBufferChains];
size_t iovec_len = fillIovec(flowPrimingBuf, vec);
socket_->write(conn_->peerAddress, vec, iovec_len);
}
handshakeLayer->connect(hostname_, std::move(paramsExtension));

View File

@ -9,6 +9,17 @@
namespace quic {
size_t fillIovec(std::unique_ptr<folly::IOBuf>& buf, iovec (&vec)[16]) {
size_t iovec_len = buf->fillIov(vec, sizeof(vec) / sizeof(vec[0])).numIovecs;
if (FOLLY_UNLIKELY(iovec_len == 0)) {
buf->coalesce();
vec[0].iov_base = const_cast<uint8_t*>(buf->data());
vec[0].iov_len = buf->length();
iovec_len = 1;
}
return iovec_len;
}
Buf BufQueue::splitAtMost(size_t len) {
folly::IOBuf* current = chain_.get();
// empty queue / requested 0 bytes

View File

@ -13,6 +13,8 @@
namespace quic {
size_t fillIovec(std::unique_ptr<folly::IOBuf>& buf, iovec (&vec)[16]);
class BufQueue {
public:
BufQueue() = default;

View File

@ -821,5 +821,26 @@ std::unique_ptr<folly::IOBuf> getProtectionKey() {
folly::IOBuf::create(0),
pnCipher->keyLength());
}
size_t getTotalIovecLen(const struct iovec* vec, size_t iovec_len) {
uint32_t result = 0;
for (uint32_t i = 0; i < iovec_len; i++) {
result += vec[i].iov_len;
}
return result;
}
Buf copyChain(Buf&& input) {
folly::IOBuf* current = input.get();
Buf headCopy = folly::IOBuf::copyBuffer(current->data(), current->length());
current = current->next();
while (current != input.get()) {
Buf currCopy = folly::IOBuf::copyBuffer(current->data(), current->length());
headCopy->appendToChain(std::move(currCopy));
current = current->next();
}
return headCopy;
}
} // namespace test
} // namespace quic

View File

@ -580,5 +580,9 @@ class FakeServerHandshake : public FizzServerHandshake {
Optional<uint64_t> clientActiveConnectionIdLimit_;
};
size_t getTotalIovecLen(const struct iovec* vec, size_t iovec_len);
Buf copyChain(Buf&& input);
} // namespace test
} // namespace quic

View File

@ -26,7 +26,7 @@ struct MockAsyncUDPSocket : public FollyQuicAsyncUDPSocket {
MOCK_METHOD(
ssize_t,
write,
(const folly::SocketAddress&, const std::unique_ptr<folly::IOBuf>&));
(const folly::SocketAddress&, const struct iovec*, size_t));
MOCK_METHOD(
int,
writem,
@ -37,7 +37,8 @@ struct MockAsyncUDPSocket : public FollyQuicAsyncUDPSocket {
ssize_t,
writeGSO,
(const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>&,
const struct iovec*,
size_t,
QuicAsyncUDPSocket::WriteOptions));
MOCK_METHOD(
ssize_t,

View File

@ -57,8 +57,11 @@ void FollyQuicAsyncUDPSocket::setErrMessageCallback(
ssize_t FollyQuicAsyncUDPSocket::write(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf) {
return follySocket_.write(address, buf);
const struct iovec* vec,
size_t iovec_len) {
folly::AsyncUDPSocket::WriteOptions writeOptions(
0 /*gsoVal*/, false /* zerocopyVal*/);
return follySocket_.writev(address, vec, iovec_len, writeOptions);
}
int FollyQuicAsyncUDPSocket::writem(
@ -70,12 +73,13 @@ int FollyQuicAsyncUDPSocket::writem(
ssize_t FollyQuicAsyncUDPSocket::writeGSO(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t iovec_len,
WriteOptions options) {
folly::AsyncUDPSocket::WriteOptions follyOptions(
options.gso, options.zerocopy);
follyOptions.txTime = options.txTime;
return follySocket_.writeGSO(address, buf, follyOptions);
return follySocket_.writev(address, vec, iovec_len, follyOptions);
}
int FollyQuicAsyncUDPSocket::writemGSO(

View File

@ -70,7 +70,8 @@ class FollyQuicAsyncUDPSocket : public QuicAsyncUDPSocketImpl {
ssize_t write(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf) override;
const struct iovec* vec,
size_t iovec_len) override;
int writem(
folly::Range<folly::SocketAddress const*> addrs,
@ -79,7 +80,8 @@ class FollyQuicAsyncUDPSocket : public QuicAsyncUDPSocketImpl {
ssize_t writeGSO(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t iovec_len,
WriteOptions options) override;
/**

View File

@ -74,7 +74,8 @@ void LibevQuicAsyncUDPSocket::pauseWrite() {
ssize_t LibevQuicAsyncUDPSocket::write(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf) {
const struct iovec* vec,
size_t iovec_len) {
if (fd_ == -1) {
throw folly::AsyncSocketException(
folly::AsyncSocketException::NOT_OPEN, "socket is not initialized");
@ -97,15 +98,6 @@ ssize_t LibevQuicAsyncUDPSocket::write(
msg.msg_namelen = 0;
}
iovec vec[16];
size_t iovec_len = buf->fillIov(vec, sizeof(vec) / sizeof(vec[0])).numIovecs;
if (UNLIKELY(iovec_len == 0)) {
buf->coalesce();
vec[0].iov_base = const_cast<uint8_t*>(buf->data());
vec[0].iov_len = buf->length();
iovec_len = 1;
}
msg.msg_iov = const_cast<struct iovec*>(vec);
msg.msg_iovlen = iovec_len;
msg.msg_control = nullptr;

View File

@ -36,7 +36,8 @@ class LibevQuicAsyncUDPSocket : public QuicAsyncUDPSocketImpl {
ssize_t write(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf) override;
const struct iovec* vec,
size_t iovec_len) override;
int writem(
folly::Range<folly::SocketAddress const*> addrs,
@ -45,7 +46,8 @@ class LibevQuicAsyncUDPSocket : public QuicAsyncUDPSocketImpl {
ssize_t writeGSO(
const folly::SocketAddress& /*address*/,
const std::unique_ptr<folly::IOBuf>& /*buf*/,
const struct iovec* /* vec */,
size_t /* iovec_len */,
WriteOptions /*options*/) override {
LOG(FATAL) << __func__ << " not supported in LibevQuicAsyncUDPSocket";
}

View File

@ -156,7 +156,8 @@ class QuicAsyncUDPSocket {
*/
virtual ssize_t write(
const folly::SocketAddress& /* address */,
const std::unique_ptr<folly::IOBuf>& /* buf */) = 0;
const struct iovec* vec,
size_t iovec_len) = 0;
/**
* Send the data in buffers to destination. Returns the return code from
@ -189,7 +190,8 @@ class QuicAsyncUDPSocket {
*/
virtual ssize_t writeGSO(
const folly::SocketAddress& address,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t iovec_len,
WriteOptions options) = 0;
/**

View File

@ -24,7 +24,7 @@ class QuicAsyncUDPSocketMock : public QuicAsyncUDPSocket {
MOCK_METHOD(
(ssize_t),
write,
(const folly::SocketAddress&, const std::unique_ptr<folly::IOBuf>&));
(const folly::SocketAddress&, const struct iovec* vec, size_t iovec_len));
MOCK_METHOD(
(int),
writem,
@ -35,7 +35,8 @@ class QuicAsyncUDPSocketMock : public QuicAsyncUDPSocket {
ssize_t,
writeGSO,
(const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>&,
const struct iovec* vec,
size_t iovec_len,
WriteOptions));
MOCK_METHOD(
(int),

View File

@ -60,7 +60,11 @@ TYPED_TEST_P(QuicAsyncUDPSocketTest, ErrToNonExistentServer) {
// If an error is received, the read callback should not be triggered
EXPECT_CALL(this->readCb_, onNotifyDataAvailable_(testing::_)).Times(0);
#endif // FOLLY_HAVE_MSG_ERRQUEUE
this->udpSocket_->write(addr, folly::IOBuf::copyBuffer("hey"));
auto sendBuf = folly::IOBuf::copyBuffer("hey");
iovec vec[quic::kNumIovecBufferChains];
size_t iovec_len =
sendBuf->fillIov(vec, sizeof(vec) / sizeof(vec[0])).numIovecs;
this->udpSocket_->write(addr, vec, iovec_len);
this->udpSocket_->getEventBase()->loopForever();
EXPECT_TRUE(errRecvd);
}
@ -72,7 +76,12 @@ TYPED_TEST_P(QuicAsyncUDPSocketTest, TestUnsetErrCallback) {
folly::SocketAddress addr("127.0.0.1", 10000);
EXPECT_CALL(this->errCb_, errMessage_(testing::_)).Times(0);
EXPECT_CALL(this->readCb_, onNotifyDataAvailable_(testing::_)).Times(0);
this->udpSocket_->write(addr, folly::IOBuf::copyBuffer("hey"));
auto sendBuf = folly::IOBuf::copyBuffer("hey");
iovec vec[quic::kNumIovecBufferChains];
size_t iovec_len =
sendBuf->fillIov(vec, sizeof(vec) / sizeof(vec[0])).numIovecs;
this->udpSocket_->write(addr, vec, iovec_len);
class EvbTerminateTimeout : public quic::QuicTimerCallback {
public:
@ -113,7 +122,11 @@ TYPED_TEST_P(QuicAsyncUDPSocketTest, CloseInErrorCallback) {
// should not be triggered
EXPECT_CALL(this->readCb_, onNotifyDataAvailable_(testing::_)).Times(0);
#endif // FOLLY_HAVE_MSG_ERRQUEUE
this->udpSocket_->write(addr, folly::IOBuf::copyBuffer("hey"));
auto sendBuf = folly::IOBuf::copyBuffer("hey");
iovec vec[quic::kNumIovecBufferChains];
size_t iovec_len =
sendBuf->fillIov(vec, sizeof(vec) / sizeof(vec[0])).numIovecs;
this->udpSocket_->write(addr, vec, iovec_len);
this->udpSocket_->getEventBase()->loopForever();
EXPECT_TRUE(errRecvd);
}

View File

@ -171,18 +171,20 @@ TEST_F(DSRMultiWriteTest, TwoRequestsWithLoss) {
std::vector<Buf> sentData;
auto sock = std::make_unique<NiceMock<quic::test::MockAsyncUDPSocket>>(qEvb_);
EXPECT_CALL(*sock, writeGSO(conn_.peerAddress, _, _))
EXPECT_CALL(*sock, writeGSO(conn_.peerAddress, _, _, _))
.WillRepeatedly(Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf,
const struct iovec* vec,
size_t iovec_len,
QuicAsyncUDPSocket::WriteOptions) {
sentData.push_back(buf->clone());
return buf->computeChainDataLength();
sentData.push_back(copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*sock, write(conn_.peerAddress, _))
EXPECT_CALL(*sock, write(conn_.peerAddress, _, _))
.WillRepeatedly(Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
sentData.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
sentData.push_back(copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
auto& instruction = pendingInstructions_.front();
CipherBuilder builder;

View File

@ -1057,7 +1057,7 @@ TEST_F(QuicClientTransportTest, FirstPacketProcessedCallback) {
TEST_F(QuicClientTransportTest, CloseSocketOnWriteError) {
client->addNewPeerAddress(serverAddr);
EXPECT_CALL(*sock, write(_, _)).WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(*sock, write(_, _, _)).WillOnce(SetErrnoAndReturn(EBADF, -1));
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_FALSE(client->isClosed());
@ -1162,11 +1162,13 @@ TEST_F(QuicClientTransportTest, SocketClosedDuringOnTransportReady) {
ConnectionCallbackThatWritesOnTransportReady callback(client);
EXPECT_CALL(callback, onTransportReadyMock());
EXPECT_CALL(callback, onReplaySafe()).Times(0);
ON_CALL(*sock, write(_, _))
ON_CALL(*sock, write(_, _, _))
.WillByDefault(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
;
}));
ON_CALL(*sock, address()).WillByDefault(ReturnRef(serverAddr));
@ -1181,7 +1183,8 @@ TEST_F(QuicClientTransportTest, NetworkUnreachableIsFatalToConn) {
client->addNewPeerAddress(serverAddr);
setupCryptoLayer();
EXPECT_CALL(clientConnSetupCallback, onConnectionSetupError(_));
EXPECT_CALL(*sock, write(_, _)).WillOnce(SetErrnoAndReturn(ENETUNREACH, -1));
EXPECT_CALL(*sock, write(_, _, _))
.WillOnce(SetErrnoAndReturn(ENETUNREACH, -1));
client->start(&clientConnSetupCallback, &clientConnCallback);
loopForWrites();
}
@ -1380,14 +1383,16 @@ class QuicClientTransportHappyEyeballsTest
auto& conn = client->getConn();
setupInitialDcidForRetry();
auto firstPacketType = GetParam();
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
setConnectionIds();
@ -1406,7 +1411,7 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_CALL(clientConnSetupCallback, onTransportReady());
EXPECT_CALL(clientConnSetupCallback, onReplaySafe());
}
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
EXPECT_CALL(*secondSock, pauseRead());
EXPECT_CALL(*secondSock, close());
if (firstPacketType == ServerFirstPacketType::Retry) {
@ -1428,13 +1433,15 @@ class QuicClientTransportHappyEyeballsTest
auto firstPacketType = GetParam();
setupInitialDcidForRetry();
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
setConnectionIds();
@ -1458,13 +1465,15 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(secondAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
EXPECT_EQ(socketWrites.size(), 1);
@ -1477,14 +1486,16 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_CALL(clientConnSetupCallback, onTransportReady());
EXPECT_CALL(clientConnSetupCallback, onReplaySafe());
}
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
EXPECT_CALL(*secondSock, pauseRead());
EXPECT_CALL(*secondSock, close());
if (firstPacketType == ServerFirstPacketType::Retry) {
@ -1506,13 +1517,15 @@ class QuicClientTransportHappyEyeballsTest
auto firstPacketType = GetParam();
setupInitialDcidForRetry();
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
setConnectionIds();
EXPECT_EQ(conn.peerAddress, firstAddress);
@ -1536,12 +1549,14 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.WillOnce(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
@ -1556,15 +1571,17 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_CALL(clientConnSetupCallback, onTransportReady());
EXPECT_CALL(clientConnSetupCallback, onReplaySafe());
}
EXPECT_CALL(*sock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(_, _, _)).Times(0);
EXPECT_CALL(*sock, pauseRead());
EXPECT_CALL(*sock, close());
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Invoke([&](const SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
if (firstPacketType == ServerFirstPacketType::Retry) {
recvServerRetry(secondAddress);
@ -1584,7 +1601,7 @@ class QuicClientTransportHappyEyeballsTest
auto& conn = client->getConn();
setupInitialDcidForRetry();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, bind(_))
.WillOnce(Invoke(
[](const folly::SocketAddress&) { throw std::exception(); }));
@ -1603,9 +1620,9 @@ class QuicClientTransportHappyEyeballsTest
auto& conn = client->getConn();
TransportSettings settings;
client->setTransportSettings(settings);
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
EXPECT_CALL(*secondSock, write(_, _));
EXPECT_CALL(*secondSock, write(_, _, _));
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1615,8 +1632,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout()
.isTimerCallbackScheduled());
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _));
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1625,13 +1642,13 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& firstAddress,
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
// Socket is paused read once during happy eyeballs
// Socket is paused read for the second time when QuicClientTransport dies
EXPECT_CALL(*sock, pauseRead()).Times(2);
EXPECT_CALL(*sock, close()).Times(1);
EXPECT_CALL(*secondSock, write(_, _));
EXPECT_CALL(*secondSock, write(_, _, _));
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1641,8 +1658,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout()
.isTimerCallbackScheduled());
EXPECT_CALL(*sock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _));
EXPECT_CALL(*sock, write(_, _, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _, _));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1652,7 +1669,7 @@ class QuicClientTransportHappyEyeballsTest
[[maybe_unused]] const SocketAddress& secondAddress) {
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*sock, write(firstAddress, _, _));
// Socket is paused read once during happy eyeballs
// Socket is paused read for the second time when QuicClientTransport dies
EXPECT_CALL(*sock, pauseRead()).Times(2);
@ -1677,8 +1694,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout()
.isTimerCallbackScheduled());
EXPECT_CALL(*sock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _));
EXPECT_CALL(*sock, write(_, _, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _, _));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
#endif
@ -1689,8 +1706,8 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1707,17 +1724,17 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
EXPECT_CALL(*secondSock, write(secondAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(firstAddress, _)).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _)).Times(1);
EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1727,8 +1744,8 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1745,21 +1762,21 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
// Socket is paused read once during happy eyeballs
// Socket is paused read for the second time when QuicClientTransport dies
EXPECT_CALL(*sock, pauseRead()).Times(2);
EXPECT_CALL(*sock, close()).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _)).Times(1);
EXPECT_CALL(*sock, write(_, _, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1770,8 +1787,8 @@ class QuicClientTransportHappyEyeballsTest
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1804,8 +1821,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _)).Times(1);
EXPECT_CALL(*sock, write(_, _, _)).Times(0);
EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
#endif
@ -1816,8 +1833,8 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1834,8 +1851,8 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
@ -1843,8 +1860,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(firstAddress, _)).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _)).Times(1);
EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1854,8 +1871,8 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1872,8 +1889,8 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
// Socket is paused read once during happy eyeballs
// Socket is paused read for the second time when QuicClientTransport dies
@ -1885,8 +1902,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(firstAddress, _)).Times(1);
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1897,8 +1914,8 @@ class QuicClientTransportHappyEyeballsTest
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1915,7 +1932,7 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*sock, write(firstAddress, _, _));
union {
struct cmsghdr hdr;
unsigned char buf[CMSG_SPACE(sizeof(sock_extended_err))];
@ -1936,8 +1953,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(firstAddress, _)).Times(1);
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
#endif
@ -1948,8 +1965,8 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -1966,9 +1983,9 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.WillOnce(SetErrnoAndReturn(EAGAIN, -1));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
@ -1976,8 +1993,8 @@ class QuicClientTransportHappyEyeballsTest
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket);
EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket);
EXPECT_CALL(*sock, write(firstAddress, _)).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _)).Times(1);
EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1);
EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1);
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
}
@ -1987,8 +2004,8 @@ class QuicClientTransportHappyEyeballsTest
const SocketAddress& secondAddress) {
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -2005,9 +2022,9 @@ class QuicClientTransportHappyEyeballsTest
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.WillOnce(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(clientConnSetupCallback, onConnectionSetupError(_));
client->lossTimeout().cancelTimerCallback();
@ -2023,8 +2040,8 @@ class QuicClientTransportHappyEyeballsTest
#ifdef FOLLY_HAVE_MSG_ERRQUEUE
auto& conn = client->getConn();
EXPECT_CALL(*sock, write(firstAddress, _));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(firstAddress, _, _));
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
client->start(&clientConnSetupCallback, &clientConnCallback);
EXPECT_EQ(conn.peerAddress, firstAddress);
EXPECT_EQ(conn.happyEyeballsState.secondPeerAddress, secondAddress);
@ -3996,11 +4013,12 @@ TEST_F(QuicClientTransportVersionAndRetryTest, RetryPacket) {
std::unique_ptr<IOBuf> bytesWrittenToNetwork = nullptr;
EXPECT_CALL(*sock, write(_, _))
EXPECT_CALL(*sock, write(_, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
bytesWrittenToNetwork = buf->clone();
return buf->computeChainDataLength();
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
bytesWrittenToNetwork =
copyChain(folly::IOBuf::wrapIov(vec, iovec_len));
return getTotalIovecLen(vec, iovec_len);
}));
auto serverCid = recvServerRetry(serverAddr);
@ -4637,7 +4655,8 @@ TEST_F(QuicClientTransportAfterStartTest, WriteThrowsExceptionWhileDraining) {
auto err = QuicError(
QuicErrorCode(LocalErrorCode::INTERNAL_ERROR),
toString(LocalErrorCode::INTERNAL_ERROR).str());
EXPECT_CALL(*sock, write(_, _)).WillRepeatedly(SetErrnoAndReturn(EBADF, -1));
EXPECT_CALL(*sock, write(_, _, _))
.WillRepeatedly(SetErrnoAndReturn(EBADF, -1));
client->close(err);
EXPECT_FALSE(client->idleTimeout().isTimerCallbackScheduled());
}
@ -4860,13 +4879,15 @@ TEST_F(QuicClientTransportAfterStartTest, OneCloseFramePerRtt) {
auto streamId = client->createBidirectionalStream().value();
auto& conn = client->getNonConstConn();
conn.lossState.srtt = 10s;
EXPECT_CALL(*sock, write(_, _)).WillRepeatedly(Return(100));
EXPECT_CALL(*sock, write(_, _, _)).WillRepeatedly(Return(100));
loopForWrites();
Mock::VerifyAndClearExpectations(sock);
// Close the client transport. There could be multiple writes given how many
// ciphers we have.
EXPECT_CALL(*sock, write(_, _)).Times(AtLeast(1)).WillRepeatedly(Return(10));
EXPECT_CALL(*sock, write(_, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Return(10));
client->close(QuicError(
QuicErrorCode(LocalErrorCode::INTERNAL_ERROR),
toString(LocalErrorCode::INTERNAL_ERROR).str()));
@ -4874,7 +4895,7 @@ TEST_F(QuicClientTransportAfterStartTest, OneCloseFramePerRtt) {
Mock::VerifyAndClearExpectations(sock);
// Then received some server packet, which won't trigger another close
EXPECT_CALL(*sock, write(_, _)).Times(0);
EXPECT_CALL(*sock, write(_, _, _)).Times(0);
auto firstData = folly::IOBuf::copyBuffer(
"I got a room full of your posters and your pictures, man");
deliverDataWithoutErrorCheck(packetToBuf(createStreamPacket(
@ -4892,7 +4913,9 @@ TEST_F(QuicClientTransportAfterStartTest, OneCloseFramePerRtt) {
conn.lastCloseSentTime = Clock::now() - 10s;
conn.lossState.srtt = 1us;
// Receive another server packet
EXPECT_CALL(*sock, write(_, _)).Times(AtLeast(1)).WillRepeatedly(Return(10));
EXPECT_CALL(*sock, write(_, _, _))
.Times(AtLeast(1))
.WillRepeatedly(Return(10));
auto secondData = folly::IOBuf::copyBuffer(
"Dear Slim, I wrote to you but you still ain't callin'");
deliverDataWithoutErrorCheck(packetToBuf(createStreamPacket(
@ -5424,13 +5447,14 @@ TEST_F(
[&](const Optional<std::string>&, const Buf&) { return true; },
[]() -> Buf { return nullptr; });
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(_, _)).Times(0);
EXPECT_CALL(*secondSock, write(_, _, _)).Times(0);
startClient();
socketWrites.clear();
auto& conn = client->getConn();
@ -5460,20 +5484,21 @@ TEST_F(
// Manually expire loss timeout to trigger write to both first and second
// socket
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.Times(2)
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWrites.push_back(
folly::IOBuf::copyBuffer(buf->data(), buf->length(), 0, 0));
return buf->length();
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.Times(2)
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();
@ -5515,11 +5540,12 @@ TEST_F(
[&](const Optional<std::string>&, const Buf&) { return true; },
[]() -> Buf { return nullptr; });
EXPECT_CALL(*sock, write(firstAddress, _))
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
startClient();
socketWrites.clear();
@ -5529,9 +5555,8 @@ TEST_F(
ASSERT_TRUE(client->happyEyeballsConnAttemptDelayTimeout()
.isTimerCallbackScheduled());
EXPECT_CALL(*sock, write(firstAddress, _))
.WillOnce(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>&) {
EXPECT_CALL(*sock, write(firstAddress, _, _))
.WillOnce(Invoke([&](const SocketAddress&, const struct iovec*, size_t) {
errno = EBADF;
return -1;
}));
@ -5546,12 +5571,13 @@ TEST_F(
EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout()
.isTimerCallbackScheduled());
EXPECT_CALL(*secondSock, write(secondAddress, _))
EXPECT_CALL(*secondSock, write(secondAddress, _, _))
.Times(2)
.WillRepeatedly(Invoke(
[&](const SocketAddress&, const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
[&](const SocketAddress&, const struct iovec* vec, size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
client->lossTimeout().cancelTimerCallback();
client->lossTimeout().timeoutExpired();

View File

@ -489,12 +489,13 @@ class QuicClientTransportTestBase : public virtual testing::Test {
void startTransport() {
client->addNewPeerAddress(serverAddr);
client->setHostname(hostname_);
ON_CALL(*sock, write(testing::_, testing::_))
.WillByDefault(
testing::Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
socketWrites.push_back(buf->clone());
return buf->computeChainDataLength();
ON_CALL(*sock, write(testing::_, testing::_, testing::_))
.WillByDefault(testing::Invoke([&](const folly::SocketAddress&,
const struct iovec* vec,
size_t iovec_len) {
socketWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
ON_CALL(*sock, address()).WillByDefault(testing::ReturnRef(serverAddr));
@ -575,7 +576,7 @@ class QuicClientTransportTestBase : public virtual testing::Test {
EXPECT_CALL(*sock, setErrMessageCallback(client.get()));
EXPECT_CALL(*sock, resumeRead(client.get()));
EXPECT_CALL(*sock, setErrMessageCallback(nullptr));
EXPECT_CALL(*sock, write(testing::_, testing::_))
EXPECT_CALL(*sock, write(testing::_, testing::_, testing::_))
.Times(testing::AtLeast(1));
}

View File

@ -144,12 +144,13 @@ class QuicServerTransportTestBase : public virtual testing::Test {
std::make_unique<testing::NiceMock<quic::test::MockAsyncUDPSocket>>(
qEvb_);
socket = sock.get();
EXPECT_CALL(*sock, write(testing::_, testing::_))
.WillRepeatedly(
testing::Invoke([&](const folly::SocketAddress&,
const std::unique_ptr<folly::IOBuf>& buf) {
serverWrites.push_back(buf->clone());
return buf->computeChainDataLength();
EXPECT_CALL(*sock, write(testing::_, testing::_, testing::_))
.WillRepeatedly(testing::Invoke([&](const folly::SocketAddress&,
const struct iovec* vec,
size_t iovec_len) {
serverWrites.push_back(
copyChain(folly::IOBuf::wrapIov(vec, iovec_len)));
return getTotalIovecLen(vec, iovec_len);
}));
EXPECT_CALL(*sock, address())
.WillRepeatedly(testing::ReturnRef(serverAddr));