diff --git a/quic/fizz/client/test/QuicClientTransportTest.cpp b/quic/fizz/client/test/QuicClientTransportTest.cpp index 5301e2afe..88be7cdd5 100644 --- a/quic/fizz/client/test/QuicClientTransportTest.cpp +++ b/quic/fizz/client/test/QuicClientTransportTest.cpp @@ -1664,10 +1664,10 @@ class QuicClientTransportHappyEyeballsTest client->lossTimeout().timeoutExpired(); } +#ifdef FOLLY_HAVE_MSG_ERRQUEUE void fatalReadErrorOnFirstBeforeSecondStarts( [[maybe_unused]] const SocketAddress& firstAddress, [[maybe_unused]] const SocketAddress& secondAddress) { -#ifdef FOLLY_HAVE_MSG_ERRQUEUE auto& conn = client->getConn(); EXPECT_CALL(*sock, write(firstAddress, _, _)); // Socket is paused read once during happy eyeballs @@ -1698,12 +1698,11 @@ class QuicClientTransportHappyEyeballsTest EXPECT_CALL(*secondSock, write(secondAddress, _, _)); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); -#endif } - void nonFatalWriteErrorOnFirstAfterSecondStarts( - const SocketAddress& firstAddress, - const SocketAddress& secondAddress) { + void fatalReadErrorOnFirstAfterSecondStarts( + [[maybe_unused]] const SocketAddress& firstAddress, + [[maybe_unused]] const SocketAddress& secondAddress) { auto& conn = client->getConn(); EXPECT_CALL(*sock, write(firstAddress, _, _)); @@ -1722,26 +1721,33 @@ class QuicClientTransportHappyEyeballsTest EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout() .isTimerCallbackScheduled()); - // Manually expire loss timeout to trigger write to both first and second - // socket - EXPECT_CALL(*sock, write(firstAddress, _, _)) - .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); - EXPECT_CALL(*secondSock, write(secondAddress, _, _)); - client->lossTimeout().cancelTimerCallback(); - client->lossTimeout().timeoutExpired(); + EXPECT_CALL(*sock, pauseRead()).Times(2); + EXPECT_CALL(*sock, close()).Times(1); - EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket); + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(sock_extended_err))]; + } cmsgbuf; + cmsgbuf.hdr.cmsg_level = SOL_IPV6; + cmsgbuf.hdr.cmsg_type = IPV6_RECVERR; + struct sock_extended_err err {}; + err.ee_errno = EBADF; + auto dest = (struct sock_extended_err*)CMSG_DATA(&cmsgbuf.hdr); + *dest = err; + client->errMessage(cmsgbuf.hdr); + + EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket); EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); - EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1); + EXPECT_CALL(*sock, write(_, _, _)).Times(0); EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); } - void fatalWriteErrorOnFirstAfterSecondStarts( - const SocketAddress& firstAddress, - const SocketAddress& secondAddress) { + void fatalReadErrorOnSecondAfterSecondStarts( + [[maybe_unused]] const SocketAddress& firstAddress, + [[maybe_unused]] const SocketAddress& secondAddress) { auto& conn = client->getConn(); EXPECT_CALL(*sock, write(firstAddress, _, _)); @@ -1762,29 +1768,36 @@ class QuicClientTransportHappyEyeballsTest // Manually expire loss timeout to trigger write to both first and second // socket - EXPECT_CALL(*sock, write(firstAddress, _, _)) - .WillOnce(SetErrnoAndReturn(EBADF, -1)); + EXPECT_CALL(*sock, write(firstAddress, _, _)); + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(sock_extended_err))]; + } cmsgbuf; + cmsgbuf.hdr.cmsg_level = SOL_IP; + cmsgbuf.hdr.cmsg_type = IP_RECVERR; + struct sock_extended_err err {}; + err.ee_errno = EBADF; + auto dest = (struct sock_extended_err*)CMSG_DATA(&cmsgbuf.hdr); + *dest = err; + client->errMessage(cmsgbuf.hdr); // 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, pauseRead()).Times(1); + EXPECT_CALL(*secondSock, close()).Times(1); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); - EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket); - EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); + EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket); + EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); - EXPECT_CALL(*sock, write(_, _, _)).Times(0); - EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); + EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1); + EXPECT_CALL(*secondSock, write(_, _, _)).Times(0); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); } - void fatalReadErrorOnFirstAfterSecondStarts( + void fatalReadErrorOnBothAfterSecondStarts( [[maybe_unused]] const SocketAddress& firstAddress, [[maybe_unused]] const SocketAddress& secondAddress) { -#ifdef FOLLY_HAVE_MSG_ERRQUEUE auto& conn = client->getConn(); EXPECT_CALL(*sock, write(firstAddress, _, _)); @@ -1803,32 +1816,27 @@ class QuicClientTransportHappyEyeballsTest EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout() .isTimerCallbackScheduled()); - EXPECT_CALL(*sock, pauseRead()).Times(2); - EXPECT_CALL(*sock, close()).Times(1); - union { struct cmsghdr hdr; unsigned char buf[CMSG_SPACE(sizeof(sock_extended_err))]; } cmsgbuf; - cmsgbuf.hdr.cmsg_level = SOL_IPV6; - cmsgbuf.hdr.cmsg_type = IPV6_RECVERR; + cmsgbuf.hdr.cmsg_level = SOL_IP; + cmsgbuf.hdr.cmsg_type = IP_RECVERR; struct sock_extended_err err {}; err.ee_errno = EBADF; auto dest = (struct sock_extended_err*)CMSG_DATA(&cmsgbuf.hdr); *dest = err; client->errMessage(cmsgbuf.hdr); + cmsgbuf.hdr.cmsg_level = SOL_IPV6; + cmsgbuf.hdr.cmsg_type = IPV6_RECVERR; + client->errMessage(cmsgbuf.hdr); EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket); - EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); - - EXPECT_CALL(*sock, write(_, _, _)).Times(0); - EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); - client->lossTimeout().cancelTimerCallback(); - client->lossTimeout().timeoutExpired(); -#endif + EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); } +#endif - void nonFatalWriteErrorOnSecondAfterSecondStarts( + void nonFatalWriteErrorOnFirstAfterSecondStarts( const SocketAddress& firstAddress, const SocketAddress& secondAddress) { auto& conn = client->getConn(); @@ -1851,9 +1859,9 @@ 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, _, _)) .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); @@ -1866,7 +1874,7 @@ class QuicClientTransportHappyEyeballsTest client->lossTimeout().timeoutExpired(); } - void fatalWriteErrorOnSecondAfterSecondStarts( + void fatalWriteErrorOnFirstAfterSecondStarts( const SocketAddress& firstAddress, const SocketAddress& secondAddress) { auto& conn = client->getConn(); @@ -1889,29 +1897,28 @@ 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, _, _)) .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(*secondSock, pauseRead()).Times(2); - EXPECT_CALL(*secondSock, close()).Times(1); + EXPECT_CALL(*sock, pauseRead()).Times(2); + EXPECT_CALL(*sock, close()).Times(1); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); - EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket); - EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); + EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket); + EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); - EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1); - EXPECT_CALL(*secondSock, write(_, _, _)).Times(0); + EXPECT_CALL(*sock, write(_, _, _)).Times(0); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); } - void fatalReadErrorOnSecondAfterSecondStarts( - [[maybe_unused]] const SocketAddress& firstAddress, - [[maybe_unused]] const SocketAddress& secondAddress) { -#ifdef FOLLY_HAVE_MSG_ERRQUEUE + void nonFatalWriteErrorOnSecondAfterSecondStarts( + const SocketAddress& firstAddress, + const SocketAddress& secondAddress) { auto& conn = client->getConn(); EXPECT_CALL(*sock, write(firstAddress, _, _)); @@ -1933,34 +1940,21 @@ class QuicClientTransportHappyEyeballsTest // Manually expire loss timeout to trigger write to both first and second // socket EXPECT_CALL(*sock, write(firstAddress, _, _)); - union { - struct cmsghdr hdr; - unsigned char buf[CMSG_SPACE(sizeof(sock_extended_err))]; - } cmsgbuf; - cmsgbuf.hdr.cmsg_level = SOL_IP; - cmsgbuf.hdr.cmsg_type = IP_RECVERR; - struct sock_extended_err err {}; - err.ee_errno = EBADF; - auto dest = (struct sock_extended_err*)CMSG_DATA(&cmsgbuf.hdr); - *dest = err; - client->errMessage(cmsgbuf.hdr); - // Socket is paused read once during happy eyeballs - EXPECT_CALL(*secondSock, pauseRead()).Times(1); - EXPECT_CALL(*secondSock, close()).Times(1); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)) + .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket); - EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); + EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1); - EXPECT_CALL(*secondSock, write(_, _, _)).Times(0); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); -#endif } - void nonFatalWriteErrorOnBothAfterSecondStarts( + void fatalWriteErrorOnSecondAfterSecondStarts( const SocketAddress& firstAddress, const SocketAddress& secondAddress) { auto& conn = client->getConn(); @@ -1983,23 +1977,26 @@ class QuicClientTransportHappyEyeballsTest // Manually expire loss timeout to trigger write to both first and second // socket - EXPECT_CALL(*sock, write(firstAddress, _, _)) - .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); + EXPECT_CALL(*sock, write(firstAddress, _, _)); EXPECT_CALL(*secondSock, write(secondAddress, _, _)) - .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); + .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(*secondSock, pauseRead()).Times(2); + EXPECT_CALL(*secondSock, close()).Times(1); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket); - EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); + EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1); - EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); + EXPECT_CALL(*secondSock, write(_, _, _)).Times(0); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); } - void fatalWriteErrorOnBothAfterSecondStarts( + void nonFatalWriteErrorOnBothAfterSecondStarts( const SocketAddress& firstAddress, const SocketAddress& secondAddress) { auto& conn = client->getConn(); @@ -2023,21 +2020,24 @@ class QuicClientTransportHappyEyeballsTest // Manually expire loss timeout to trigger write to both first and second // socket EXPECT_CALL(*sock, write(firstAddress, _, _)) - .WillOnce(SetErrnoAndReturn(EBADF, -1)); + .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); EXPECT_CALL(*secondSock, write(secondAddress, _, _)) - .WillOnce(SetErrnoAndReturn(EBADF, -1)); - EXPECT_CALL(clientConnSetupCallback, onConnectionSetupError(_)); + .WillOnce(SetErrnoAndReturn(EAGAIN, -1)); client->lossTimeout().cancelTimerCallback(); client->lossTimeout().timeoutExpired(); - EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket); - EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); + EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToFirstSocket); + EXPECT_TRUE(conn.happyEyeballsState.shouldWriteToSecondSocket); + + EXPECT_CALL(*sock, write(firstAddress, _, _)).Times(1); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)).Times(1); + client->lossTimeout().cancelTimerCallback(); + client->lossTimeout().timeoutExpired(); } - void fatalReadErrorOnBothAfterSecondStarts( - [[maybe_unused]] const SocketAddress& firstAddress, - [[maybe_unused]] const SocketAddress& secondAddress) { -#ifdef FOLLY_HAVE_MSG_ERRQUEUE + void fatalWriteErrorOnBothAfterSecondStarts( + const SocketAddress& firstAddress, + const SocketAddress& secondAddress) { auto& conn = client->getConn(); EXPECT_CALL(*sock, write(firstAddress, _, _)); @@ -2056,24 +2056,18 @@ class QuicClientTransportHappyEyeballsTest EXPECT_FALSE(client->happyEyeballsConnAttemptDelayTimeout() .isTimerCallbackScheduled()); - union { - struct cmsghdr hdr; - unsigned char buf[CMSG_SPACE(sizeof(sock_extended_err))]; - } cmsgbuf; - cmsgbuf.hdr.cmsg_level = SOL_IP; - cmsgbuf.hdr.cmsg_type = IP_RECVERR; - struct sock_extended_err err {}; - err.ee_errno = EBADF; - auto dest = (struct sock_extended_err*)CMSG_DATA(&cmsgbuf.hdr); - *dest = err; - client->errMessage(cmsgbuf.hdr); - cmsgbuf.hdr.cmsg_level = SOL_IPV6; - cmsgbuf.hdr.cmsg_type = IPV6_RECVERR; - client->errMessage(cmsgbuf.hdr); + // Manually expire loss timeout to trigger write to both first and second + // socket + EXPECT_CALL(*sock, write(firstAddress, _, _)) + .WillOnce(SetErrnoAndReturn(EBADF, -1)); + EXPECT_CALL(*secondSock, write(secondAddress, _, _)) + .WillOnce(SetErrnoAndReturn(EBADF, -1)); + EXPECT_CALL(clientConnSetupCallback, onConnectionSetupError(_)); + client->lossTimeout().cancelTimerCallback(); + client->lossTimeout().timeoutExpired(); EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToFirstSocket); EXPECT_FALSE(conn.happyEyeballsState.shouldWriteToSecondSocket); -#endif } protected: @@ -2117,6 +2111,7 @@ TEST_F( fatalWriteErrorOnFirstBeforeSecondStarts(serverAddrV6, serverAddrV4); } +#ifdef FOLLY_HAVE_MSG_ERRQUEUE TEST_F( QuicClientTransportHappyEyeballsTest, V6FirstAndV6FatalReadErrorBeforeV4Start) { @@ -2125,56 +2120,57 @@ TEST_F( TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndV6NonFatalErrorAfterV4Starts) { - nonFatalWriteErrorOnFirstAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndV6FatalReadErrorAfterV4Start) { + fatalReadErrorOnFirstAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndV6FatalErrorAfterV4Start) { - fatalWriteErrorOnFirstAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndBothFatalReadErrorAfterV4Start) { + fatalReadErrorOnBothAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndV6FatalReadErrorAfterV4Start) { - fatalReadErrorOnFirstAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndV4FatalReadErrorAfterV4Start) { + fatalReadErrorOnSecondAfterSecondStarts(serverAddrV6, serverAddrV4); } +#endif TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndV4NonFatalErrorAfterV4Start) { - nonFatalWriteErrorOnSecondAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndV6NonFatalErrorAfterV4Starts) { + nonFatalWriteErrorOnFirstAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndV4FatalErrorAfterV4Start) { - fatalWriteErrorOnSecondAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndV6FatalErrorAfterV4Start) { + fatalWriteErrorOnFirstAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndV4FatalReadErrorAfterV4Start) { - fatalReadErrorOnSecondAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndV4NonFatalErrorAfterV4Start) { + nonFatalWriteErrorOnSecondAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndBothNonFatalErrorAfterV4Start) { - nonFatalWriteErrorOnBothAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndV4FatalErrorAfterV4Start) { + fatalWriteErrorOnSecondAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndBothFatalErrorAfterV4Start) { - fatalWriteErrorOnBothAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndBothNonFatalErrorAfterV4Start) { + nonFatalWriteErrorOnBothAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_F( QuicClientTransportHappyEyeballsTest, - V6FirstAndBothFatalReadErrorAfterV4Start) { - fatalReadErrorOnBothAfterSecondStarts(serverAddrV6, serverAddrV4); + V6FirstAndBothFatalErrorAfterV4Start) { + fatalWriteErrorOnBothAfterSecondStarts(serverAddrV6, serverAddrV4); } TEST_P(QuicClientTransportHappyEyeballsTest, V4FirstAndV4WinBeforeV6Start) {