1 /* 2 * libjingle 3 * Copyright 2012, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 #if defined(POSIX) 28 #include <dirent.h> 29 #endif 30 31 #include "talk/base/asynctcpsocket.h" 32 #include "talk/base/buffer.h" 33 #include "talk/base/dscp.h" 34 #include "talk/base/firewallsocketserver.h" 35 #include "talk/base/logging.h" 36 #include "talk/base/gunit.h" 37 #include "talk/base/helpers.h" 38 #include "talk/base/physicalsocketserver.h" 39 #include "talk/base/scoped_ptr.h" 40 #include "talk/base/socketaddress.h" 41 #include "talk/base/thread.h" 42 #include "talk/base/virtualsocketserver.h" 43 #include "talk/p2p/base/basicpacketsocketfactory.h" 44 #include "talk/p2p/base/constants.h" 45 #include "talk/p2p/base/tcpport.h" 46 #include "talk/p2p/base/testturnserver.h" 47 #include "talk/p2p/base/turnport.h" 48 #include "talk/p2p/base/udpport.h" 49 50 using talk_base::SocketAddress; 51 using cricket::Connection; 52 using cricket::Port; 53 using cricket::PortInterface; 54 using cricket::TurnPort; 55 using cricket::UDPPort; 56 57 static const SocketAddress kLocalAddr1("11.11.11.11", 0); 58 static const SocketAddress kLocalAddr2("22.22.22.22", 0); 59 static const SocketAddress kLocalIPv6Addr( 60 "2401:fa00:4:1000:be30:5bff:fee5:c3", 0); 61 static const SocketAddress kTurnUdpIntAddr("99.99.99.3", 62 cricket::TURN_SERVER_PORT); 63 static const SocketAddress kTurnTcpIntAddr("99.99.99.4", 64 cricket::TURN_SERVER_PORT); 65 static const SocketAddress kTurnUdpExtAddr("99.99.99.5", 0); 66 static const SocketAddress kTurnUdpIPv6IntAddr( 67 "2400:4030:1:2c00:be30:abcd:efab:cdef", cricket::TURN_SERVER_PORT); 68 static const SocketAddress kTurnUdpIPv6ExtAddr( 69 "2620:0:1000:1b03:2e41:38ff:fea6:f2a4", 0); 70 71 static const char kIceUfrag1[] = "TESTICEUFRAG0001"; 72 static const char kIceUfrag2[] = "TESTICEUFRAG0002"; 73 static const char kIcePwd1[] = "TESTICEPWD00000000000001"; 74 static const char kIcePwd2[] = "TESTICEPWD00000000000002"; 75 static const char kTurnUsername[] = "test"; 76 static const char kTurnPassword[] = "test"; 77 static const unsigned int kTimeout = 1000; 78 79 static const cricket::ProtocolAddress kTurnUdpProtoAddr( 80 kTurnUdpIntAddr, cricket::PROTO_UDP); 81 static const cricket::ProtocolAddress kTurnTcpProtoAddr( 82 kTurnTcpIntAddr, cricket::PROTO_TCP); 83 static const cricket::ProtocolAddress kTurnUdpIPv6ProtoAddr( 84 kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); 85 86 static const unsigned int MSG_TESTFINISH = 0; 87 88 #if defined(LINUX) 89 static int GetFDCount() { 90 struct dirent *dp; 91 int fd_count = 0; 92 DIR *dir = opendir("/proc/self/fd/"); 93 while ((dp = readdir(dir)) != NULL) { 94 if (dp->d_name[0] == '.') 95 continue; 96 ++fd_count; 97 } 98 closedir(dir); 99 return fd_count; 100 } 101 #endif 102 103 class TurnPortTest : public testing::Test, 104 public sigslot::has_slots<>, 105 public talk_base::MessageHandler { 106 public: 107 TurnPortTest() 108 : main_(talk_base::Thread::Current()), 109 pss_(new talk_base::PhysicalSocketServer), 110 ss_(new talk_base::VirtualSocketServer(pss_.get())), 111 ss_scope_(ss_.get()), 112 network_("unittest", "unittest", talk_base::IPAddress(INADDR_ANY), 32), 113 socket_factory_(talk_base::Thread::Current()), 114 turn_server_(main_, kTurnUdpIntAddr, kTurnUdpExtAddr), 115 turn_ready_(false), 116 turn_error_(false), 117 turn_unknown_address_(false), 118 turn_create_permission_success_(false), 119 udp_ready_(false), 120 test_finish_(false) { 121 network_.AddIP(talk_base::IPAddress(INADDR_ANY)); 122 } 123 124 virtual void OnMessage(talk_base::Message* msg) { 125 ASSERT(msg->message_id == MSG_TESTFINISH); 126 if (msg->message_id == MSG_TESTFINISH) 127 test_finish_ = true; 128 } 129 130 void OnTurnPortComplete(Port* port) { 131 turn_ready_ = true; 132 } 133 void OnTurnPortError(Port* port) { 134 turn_error_ = true; 135 } 136 void OnTurnUnknownAddress(PortInterface* port, const SocketAddress& addr, 137 cricket::ProtocolType proto, 138 cricket::IceMessage* msg, const std::string& rf, 139 bool /*port_muxed*/) { 140 turn_unknown_address_ = true; 141 } 142 void OnTurnCreatePermissionResult(TurnPort* port, const SocketAddress& addr, 143 int code) { 144 // Ignoring the address. 145 if (code == 0) { 146 turn_create_permission_success_ = true; 147 } 148 } 149 void OnTurnReadPacket(Connection* conn, const char* data, size_t size, 150 const talk_base::PacketTime& packet_time) { 151 turn_packets_.push_back(talk_base::Buffer(data, size)); 152 } 153 void OnUdpPortComplete(Port* port) { 154 udp_ready_ = true; 155 } 156 void OnUdpReadPacket(Connection* conn, const char* data, size_t size, 157 const talk_base::PacketTime& packet_time) { 158 udp_packets_.push_back(talk_base::Buffer(data, size)); 159 } 160 void OnSocketReadPacket(talk_base::AsyncPacketSocket* socket, 161 const char* data, size_t size, 162 const talk_base::SocketAddress& remote_addr, 163 const talk_base::PacketTime& packet_time) { 164 turn_port_->HandleIncomingPacket(socket, data, size, remote_addr, 165 packet_time); 166 } 167 talk_base::AsyncSocket* CreateServerSocket(const SocketAddress addr) { 168 talk_base::AsyncSocket* socket = ss_->CreateAsyncSocket(SOCK_STREAM); 169 EXPECT_GE(socket->Bind(addr), 0); 170 EXPECT_GE(socket->Listen(5), 0); 171 return socket; 172 } 173 174 void CreateTurnPort(const std::string& username, 175 const std::string& password, 176 const cricket::ProtocolAddress& server_address) { 177 CreateTurnPort(kLocalAddr1, username, password, server_address); 178 } 179 void CreateTurnPort(const talk_base::SocketAddress& local_address, 180 const std::string& username, 181 const std::string& password, 182 const cricket::ProtocolAddress& server_address) { 183 cricket::RelayCredentials credentials(username, password); 184 turn_port_.reset(TurnPort::Create(main_, &socket_factory_, &network_, 185 local_address.ipaddr(), 0, 0, 186 kIceUfrag1, kIcePwd1, 187 server_address, credentials)); 188 // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be 189 // in Hybrid mode. Protocol type is necessary to send correct type STUN ping 190 // messages. 191 // This TURN port will be the controlling. 192 turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); 193 turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); 194 ConnectSignals(); 195 } 196 197 void CreateSharedTurnPort(const std::string& username, 198 const std::string& password, 199 const cricket::ProtocolAddress& server_address) { 200 ASSERT(server_address.proto == cricket::PROTO_UDP); 201 202 socket_.reset(socket_factory_.CreateUdpSocket( 203 talk_base::SocketAddress(kLocalAddr1.ipaddr(), 0), 0, 0)); 204 ASSERT_TRUE(socket_ != NULL); 205 socket_->SignalReadPacket.connect(this, &TurnPortTest::OnSocketReadPacket); 206 207 cricket::RelayCredentials credentials(username, password); 208 turn_port_.reset(cricket::TurnPort::Create( 209 main_, &socket_factory_, &network_, socket_.get(), 210 kIceUfrag1, kIcePwd1, server_address, credentials)); 211 // Set ICE protocol type to ICEPROTO_RFC5245, as port by default will be 212 // in Hybrid mode. Protocol type is necessary to send correct type STUN ping 213 // messages. 214 // This TURN port will be the controlling. 215 turn_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); 216 turn_port_->SetIceRole(cricket::ICEROLE_CONTROLLING); 217 ConnectSignals(); 218 } 219 220 void ConnectSignals() { 221 turn_port_->SignalPortComplete.connect(this, 222 &TurnPortTest::OnTurnPortComplete); 223 turn_port_->SignalPortError.connect(this, 224 &TurnPortTest::OnTurnPortError); 225 turn_port_->SignalUnknownAddress.connect(this, 226 &TurnPortTest::OnTurnUnknownAddress); 227 turn_port_->SignalCreatePermissionResult.connect(this, 228 &TurnPortTest::OnTurnCreatePermissionResult); 229 } 230 void CreateUdpPort() { 231 udp_port_.reset(UDPPort::Create(main_, &socket_factory_, &network_, 232 kLocalAddr2.ipaddr(), 0, 0, 233 kIceUfrag2, kIcePwd2)); 234 // Set protocol type to RFC5245, as turn port is also in same mode. 235 // UDP port will be controlled. 236 udp_port_->SetIceProtocolType(cricket::ICEPROTO_RFC5245); 237 udp_port_->SetIceRole(cricket::ICEROLE_CONTROLLED); 238 udp_port_->SignalPortComplete.connect( 239 this, &TurnPortTest::OnUdpPortComplete); 240 } 241 242 void TestTurnConnection() { 243 // Create ports and prepare addresses. 244 ASSERT_TRUE(turn_port_ != NULL); 245 turn_port_->PrepareAddress(); 246 ASSERT_TRUE_WAIT(turn_ready_, kTimeout); 247 CreateUdpPort(); 248 udp_port_->PrepareAddress(); 249 ASSERT_TRUE_WAIT(udp_ready_, kTimeout); 250 251 // Send ping from UDP to TURN. 252 Connection* conn1 = udp_port_->CreateConnection( 253 turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE); 254 ASSERT_TRUE(conn1 != NULL); 255 conn1->Ping(0); 256 WAIT(!turn_unknown_address_, kTimeout); 257 EXPECT_FALSE(turn_unknown_address_); 258 EXPECT_EQ(Connection::STATE_READ_INIT, conn1->read_state()); 259 EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); 260 261 // Send ping from TURN to UDP. 262 Connection* conn2 = turn_port_->CreateConnection( 263 udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE); 264 ASSERT_TRUE(conn2 != NULL); 265 ASSERT_TRUE_WAIT(turn_create_permission_success_, kTimeout); 266 conn2->Ping(0); 267 268 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout); 269 EXPECT_EQ(Connection::STATE_READABLE, conn1->read_state()); 270 EXPECT_EQ(Connection::STATE_READ_INIT, conn2->read_state()); 271 EXPECT_EQ(Connection::STATE_WRITE_INIT, conn1->write_state()); 272 273 // Send another ping from UDP to TURN. 274 conn1->Ping(0); 275 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout); 276 EXPECT_EQ(Connection::STATE_READABLE, conn2->read_state()); 277 } 278 279 void TestTurnSendData() { 280 turn_port_->PrepareAddress(); 281 EXPECT_TRUE_WAIT(turn_ready_, kTimeout); 282 CreateUdpPort(); 283 udp_port_->PrepareAddress(); 284 EXPECT_TRUE_WAIT(udp_ready_, kTimeout); 285 // Create connections and send pings. 286 Connection* conn1 = turn_port_->CreateConnection( 287 udp_port_->Candidates()[0], Port::ORIGIN_MESSAGE); 288 Connection* conn2 = udp_port_->CreateConnection( 289 turn_port_->Candidates()[0], Port::ORIGIN_MESSAGE); 290 ASSERT_TRUE(conn1 != NULL); 291 ASSERT_TRUE(conn2 != NULL); 292 conn1->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), 293 &TurnPortTest::OnTurnReadPacket); 294 conn2->SignalReadPacket.connect(static_cast<TurnPortTest*>(this), 295 &TurnPortTest::OnUdpReadPacket); 296 conn1->Ping(0); 297 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn1->write_state(), kTimeout); 298 conn2->Ping(0); 299 EXPECT_EQ_WAIT(Connection::STATE_WRITABLE, conn2->write_state(), kTimeout); 300 301 // Send some data. 302 size_t num_packets = 256; 303 for (size_t i = 0; i < num_packets; ++i) { 304 char buf[256]; 305 for (size_t j = 0; j < i + 1; ++j) { 306 buf[j] = 0xFF - j; 307 } 308 conn1->Send(buf, i + 1, options); 309 conn2->Send(buf, i + 1, options); 310 main_->ProcessMessages(0); 311 } 312 313 // Check the data. 314 ASSERT_EQ_WAIT(num_packets, turn_packets_.size(), kTimeout); 315 ASSERT_EQ_WAIT(num_packets, udp_packets_.size(), kTimeout); 316 for (size_t i = 0; i < num_packets; ++i) { 317 EXPECT_EQ(i + 1, turn_packets_[i].length()); 318 EXPECT_EQ(i + 1, udp_packets_[i].length()); 319 EXPECT_EQ(turn_packets_[i], udp_packets_[i]); 320 } 321 } 322 323 protected: 324 talk_base::Thread* main_; 325 talk_base::scoped_ptr<talk_base::PhysicalSocketServer> pss_; 326 talk_base::scoped_ptr<talk_base::VirtualSocketServer> ss_; 327 talk_base::SocketServerScope ss_scope_; 328 talk_base::Network network_; 329 talk_base::BasicPacketSocketFactory socket_factory_; 330 talk_base::scoped_ptr<talk_base::AsyncPacketSocket> socket_; 331 cricket::TestTurnServer turn_server_; 332 talk_base::scoped_ptr<TurnPort> turn_port_; 333 talk_base::scoped_ptr<UDPPort> udp_port_; 334 bool turn_ready_; 335 bool turn_error_; 336 bool turn_unknown_address_; 337 bool turn_create_permission_success_; 338 bool udp_ready_; 339 bool test_finish_; 340 std::vector<talk_base::Buffer> turn_packets_; 341 std::vector<talk_base::Buffer> udp_packets_; 342 talk_base::PacketOptions options; 343 }; 344 345 // Do a normal TURN allocation. 346 TEST_F(TurnPortTest, TestTurnAllocate) { 347 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); 348 EXPECT_EQ(0, turn_port_->SetOption(talk_base::Socket::OPT_SNDBUF, 10*1024)); 349 turn_port_->PrepareAddress(); 350 EXPECT_TRUE_WAIT(turn_ready_, kTimeout); 351 ASSERT_EQ(1U, turn_port_->Candidates().size()); 352 EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), 353 turn_port_->Candidates()[0].address().ipaddr()); 354 EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); 355 } 356 357 TEST_F(TurnPortTest, TestTurnTcpAllocate) { 358 turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); 359 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); 360 EXPECT_EQ(0, turn_port_->SetOption(talk_base::Socket::OPT_SNDBUF, 10*1024)); 361 turn_port_->PrepareAddress(); 362 EXPECT_TRUE_WAIT(turn_ready_, kTimeout); 363 ASSERT_EQ(1U, turn_port_->Candidates().size()); 364 EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), 365 turn_port_->Candidates()[0].address().ipaddr()); 366 EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); 367 } 368 369 // Try to do a TURN allocation with an invalid password. 370 TEST_F(TurnPortTest, TestTurnAllocateBadPassword) { 371 CreateTurnPort(kTurnUsername, "bad", kTurnUdpProtoAddr); 372 turn_port_->PrepareAddress(); 373 EXPECT_TRUE_WAIT(turn_error_, kTimeout); 374 ASSERT_EQ(0U, turn_port_->Candidates().size()); 375 } 376 377 // Do a TURN allocation and try to send a packet to it from the outside. 378 // The packet should be dropped. Then, try to send a packet from TURN to the 379 // outside. It should reach its destination. Finally, try again from the 380 // outside. It should now work as well. 381 TEST_F(TurnPortTest, TestTurnConnection) { 382 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); 383 TestTurnConnection(); 384 } 385 386 // Similar to above, except that this test will use the shared socket. 387 TEST_F(TurnPortTest, TestTurnConnectionUsingSharedSocket) { 388 CreateSharedTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); 389 TestTurnConnection(); 390 } 391 392 // Test that we can establish a TCP connection with TURN server. 393 TEST_F(TurnPortTest, TestTurnTcpConnection) { 394 turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); 395 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); 396 TestTurnConnection(); 397 } 398 399 // Test that we fail to create a connection when we want to use TLS over TCP. 400 // This test should be removed once we have TLS support. 401 TEST_F(TurnPortTest, TestTurnTlsTcpConnectionFails) { 402 cricket::ProtocolAddress secure_addr(kTurnTcpProtoAddr.address, 403 kTurnTcpProtoAddr.proto, 404 true); 405 CreateTurnPort(kTurnUsername, kTurnPassword, secure_addr); 406 turn_port_->PrepareAddress(); 407 EXPECT_TRUE_WAIT(turn_error_, kTimeout); 408 ASSERT_EQ(0U, turn_port_->Candidates().size()); 409 } 410 411 // Run TurnConnectionTest with one-time-use nonce feature. 412 // Here server will send a 438 STALE_NONCE error message for 413 // every TURN transaction. 414 TEST_F(TurnPortTest, TestTurnConnectionUsingOTUNonce) { 415 turn_server_.set_enable_otu_nonce(true); 416 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); 417 TestTurnConnection(); 418 } 419 420 // Do a TURN allocation, establish a UDP connection, and send some data. 421 TEST_F(TurnPortTest, TestTurnSendDataTurnUdpToUdp) { 422 // Create ports and prepare addresses. 423 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnUdpProtoAddr); 424 TestTurnSendData(); 425 } 426 427 // Do a TURN allocation, establish a TCP connection, and send some data. 428 TEST_F(TurnPortTest, TestTurnSendDataTurnTcpToUdp) { 429 turn_server_.AddInternalSocket(kTurnTcpIntAddr, cricket::PROTO_TCP); 430 // Create ports and prepare addresses. 431 CreateTurnPort(kTurnUsername, kTurnPassword, kTurnTcpProtoAddr); 432 TestTurnSendData(); 433 } 434 435 // Test TURN fails to make a connection from IPv6 address to a server which has 436 // IPv4 address. 437 TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv4) { 438 turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); 439 CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, 440 kTurnUdpProtoAddr); 441 turn_port_->PrepareAddress(); 442 ASSERT_TRUE_WAIT(turn_error_, kTimeout); 443 EXPECT_TRUE(turn_port_->Candidates().empty()); 444 } 445 446 // Test TURN make a connection from IPv6 address to a server which has 447 // IPv6 intenal address. But in this test external address is a IPv4 address, 448 // hence allocated address will be a IPv4 address. 449 TEST_F(TurnPortTest, TestTurnLocalIPv6AddressServerIPv6ExtenalIPv4) { 450 turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); 451 CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, 452 kTurnUdpIPv6ProtoAddr); 453 turn_port_->PrepareAddress(); 454 EXPECT_TRUE_WAIT(turn_ready_, kTimeout); 455 ASSERT_EQ(1U, turn_port_->Candidates().size()); 456 EXPECT_EQ(kTurnUdpExtAddr.ipaddr(), 457 turn_port_->Candidates()[0].address().ipaddr()); 458 EXPECT_NE(0, turn_port_->Candidates()[0].address().port()); 459 } 460 461 // This test verifies any FD's are not leaked after TurnPort is destroyed. 462 // https://code.google.com/p/webrtc/issues/detail?id=2651 463 #if defined(LINUX) 464 TEST_F(TurnPortTest, TestResolverShutdown) { 465 turn_server_.AddInternalSocket(kTurnUdpIPv6IntAddr, cricket::PROTO_UDP); 466 int last_fd_count = GetFDCount(); 467 // Need to supply unresolved address to kick off resolver. 468 CreateTurnPort(kLocalIPv6Addr, kTurnUsername, kTurnPassword, 469 cricket::ProtocolAddress(talk_base::SocketAddress( 470 "stun.l.google.com", 3478), cricket::PROTO_UDP)); 471 turn_port_->PrepareAddress(); 472 ASSERT_TRUE_WAIT(turn_error_, kTimeout); 473 EXPECT_TRUE(turn_port_->Candidates().empty()); 474 turn_port_.reset(); 475 talk_base::Thread::Current()->Post(this, MSG_TESTFINISH); 476 // Waiting for above message to be processed. 477 ASSERT_TRUE_WAIT(test_finish_, kTimeout); 478 EXPECT_EQ(last_fd_count, GetFDCount()); 479 } 480 #endif 481 482