PageRenderTime 87ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/tests/socket.cpp

http://github.com/mozy/mordor
C++ | 566 lines | 487 code | 56 blank | 23 comment | 27 complexity | 10030b7e246f02b0da0cad627d40b8d5 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include <iostream>
  3. #include <boost/lexical_cast.hpp>
  4. #include <boost/scoped_array.hpp>
  5. #include <boost/shared_array.hpp>
  6. #include "mordor/exception.h"
  7. #include "mordor/fiber.h"
  8. #include "mordor/iomanager.h"
  9. #include "mordor/socket.h"
  10. #include "mordor/test/test.h"
  11. using namespace Mordor;
  12. using namespace Mordor::Test;
  13. namespace {
  14. struct Connection
  15. {
  16. Socket::ptr connect;
  17. Socket::ptr listen;
  18. Socket::ptr accept;
  19. IPAddress::ptr address;
  20. };
  21. }
  22. static void acceptOne(Connection &conns)
  23. {
  24. MORDOR_ASSERT(conns.listen);
  25. conns.accept = conns.listen->accept();
  26. }
  27. static Connection
  28. establishConn(IOManager &ioManager)
  29. {
  30. Connection result;
  31. std::vector<Address::ptr> addresses = Address::lookup("localhost");
  32. MORDOR_TEST_ASSERT(!addresses.empty());
  33. result.address = boost::dynamic_pointer_cast<IPAddress>(addresses.front());
  34. result.listen = result.address->createSocket(ioManager, SOCK_STREAM);
  35. unsigned int opt = 1;
  36. result.listen->setOption(SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  37. while (true) {
  38. try {
  39. // Random port > 1000
  40. result.address->port(rand() % 50000 + 1000);
  41. result.listen->bind(result.address);
  42. break;
  43. } catch (AddressInUseException &) {
  44. }
  45. }
  46. result.listen->listen();
  47. result.connect = result.address->createSocket(ioManager, SOCK_STREAM);
  48. return result;
  49. }
  50. MORDOR_SUITE_INVARIANT(Socket)
  51. {
  52. MORDOR_TEST_ASSERT(!Scheduler::getThis());
  53. }
  54. MORDOR_UNITTEST(Socket, acceptTimeout)
  55. {
  56. IOManager ioManager(2, true);
  57. Connection conns = establishConn(ioManager);
  58. conns.listen->receiveTimeout(200000);
  59. unsigned long long start = TimerManager::now();
  60. MORDOR_TEST_ASSERT_EXCEPTION(conns.listen->accept(), TimedOutException);
  61. MORDOR_TEST_ASSERT_ABOUT_EQUAL(start + 200000, TimerManager::now(), 100000);
  62. MORDOR_TEST_ASSERT_EXCEPTION(conns.listen->accept(), TimedOutException);
  63. }
  64. MORDOR_UNITTEST(Socket, receiveTimeout)
  65. {
  66. IOManager ioManager;
  67. Connection conns = establishConn(ioManager);
  68. conns.connect->receiveTimeout(100000);
  69. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  70. conns.connect->connect(conns.address);
  71. ioManager.dispatch();
  72. char buf;
  73. unsigned long long start = TimerManager::now();
  74. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->receive(&buf, 1), TimedOutException);
  75. MORDOR_TEST_ASSERT_ABOUT_EQUAL(start + 100000, TimerManager::now(), 50000);
  76. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->receive(&buf, 1), TimedOutException);
  77. }
  78. MORDOR_UNITTEST(Socket, sendTimeout)
  79. {
  80. IOManager ioManager;
  81. Connection conns = establishConn(ioManager);
  82. conns.connect->sendTimeout(200000);
  83. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  84. conns.connect->connect(conns.address);
  85. ioManager.dispatch();
  86. char buf[65536];
  87. memset(buf, 0, sizeof(buf));
  88. unsigned long long start = TimerManager::now();
  89. MORDOR_TEST_ASSERT_EXCEPTION(while (true) conns.connect->send(buf, sizeof(buf)), TimedOutException);
  90. MORDOR_TEST_ASSERT_ABOUT_EQUAL(start + 200000, TimerManager::now(), 500000);
  91. }
  92. class DummyException
  93. {};
  94. template <class Exception>
  95. static void testShutdownException(bool send, bool shutdown, bool otherEnd)
  96. {
  97. IOManager ioManager;
  98. Connection conns = establishConn(ioManager);
  99. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  100. conns.connect->connect(conns.address);
  101. ioManager.dispatch();
  102. Socket::ptr &socketToClose = otherEnd ? conns.accept : conns.connect;
  103. if (shutdown)
  104. socketToClose->shutdown(SHUT_RDWR);
  105. else
  106. socketToClose.reset();
  107. if (send) {
  108. if (otherEnd) {
  109. try {
  110. conns.connect->sendTimeout(100);
  111. while (true) {
  112. MORDOR_TEST_ASSERT_EQUAL(conns.connect->send("abc", 3), 3u);
  113. }
  114. } catch (const Exception&) {
  115. }
  116. } else {
  117. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->send("abc", 3), Exception);
  118. }
  119. } else {
  120. unsigned char readBuf[3];
  121. if (otherEnd) {
  122. MORDOR_TEST_ASSERT_EQUAL(conns.connect->receive(readBuf, 3), 0u);
  123. } else {
  124. #ifndef WINDOWS
  125. // Silly non-Windows letting you receive after you told it no more
  126. if (shutdown) {
  127. MORDOR_TEST_ASSERT_EQUAL(conns.connect->receive(readBuf, 3), 0u);
  128. } else
  129. #endif
  130. {
  131. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->receive(readBuf, 3), Exception);
  132. }
  133. }
  134. }
  135. }
  136. MORDOR_UNITTEST(Socket, sendAfterShutdown)
  137. {
  138. testShutdownException<BrokenPipeException>(true, true, false);
  139. }
  140. MORDOR_UNITTEST(Socket, receiveAfterShutdown)
  141. {
  142. testShutdownException<BrokenPipeException>(false, true, false);
  143. }
  144. MORDOR_UNITTEST(Socket, sendAfterCloseOtherEnd)
  145. {
  146. #ifdef WINDOWS
  147. testShutdownException<ConnectionAbortedException>(true, false, true);
  148. #else
  149. try {
  150. testShutdownException<BrokenPipeException>(true, false, true);
  151. // Could also be ConnectionReset on BSDs
  152. } catch (const ConnectionResetException&)
  153. {}
  154. #ifdef OSX
  155. // EPROTOTYPE may be thrown out on mac os 10
  156. catch (const WrongProtocolTypeException&)
  157. {}
  158. #endif
  159. #endif
  160. }
  161. MORDOR_UNITTEST(Socket, receiveAfterCloseOtherEnd)
  162. {
  163. // Exception is not used; this is special cased in testShutdownException
  164. testShutdownException<DummyException>(false, false, true);
  165. }
  166. MORDOR_UNITTEST(Socket, sendAfterShutdownOtherEnd)
  167. {
  168. #ifdef WINDOWS
  169. testShutdownException<ConnectionAbortedException>(true, false, true);
  170. #elif defined(BSD)
  171. // temporarily skip this case for further investigation
  172. throw TestSkippedException();
  173. // BSD lets you write to the socket, but it blocks, so we have to check
  174. // for it blocking
  175. testShutdownException<TimedOutException>(true, true, true);
  176. #else
  177. testShutdownException<BrokenPipeException>(true, false, true);
  178. #endif
  179. }
  180. MORDOR_UNITTEST(Socket, receiveAfterShutdownOtherEnd)
  181. {
  182. // Exception is not used; this is special cased in testShutdownException
  183. testShutdownException<DummyException>(false, true, true);
  184. }
  185. static void testAddress(const char *addr, const char *expected)
  186. {
  187. MORDOR_TEST_ASSERT_EQUAL(
  188. boost::lexical_cast<std::string>(*IPAddress::create(addr, 80)),
  189. expected);
  190. }
  191. MORDOR_UNITTEST(Address, formatIPv4Address)
  192. {
  193. testAddress("127.0.0.1", "127.0.0.1:80");
  194. }
  195. MORDOR_UNITTEST(Address, formatIPv6Address)
  196. {
  197. try {
  198. testAddress("::", "[::]:80");
  199. testAddress("::1", "[::1]:80");
  200. testAddress("[2001:470:1f05:273:20c:29ff:feb3:5ddf]",
  201. "[2001:470:1f05:273:20c:29ff:feb3:5ddf]:80");
  202. testAddress("[2001:470::273:20c:0:0:5ddf]",
  203. "[2001:470::273:20c:0:0:5ddf]:80");
  204. testAddress("[2001:470:0:0:273:20c::5ddf]",
  205. "[2001:470::273:20c:0:5ddf]:80");
  206. } catch (std::invalid_argument &) {
  207. throw TestSkippedException();
  208. }
  209. }
  210. MORDOR_UNITTEST(Address, parseIPv4Address)
  211. {
  212. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(IPv4Address(0x7f000001, 80)),
  213. "127.0.0.1:80");
  214. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(IPv4Address("127.0.0.1")),
  215. "127.0.0.1:0");
  216. MORDOR_TEST_ASSERT_EXCEPTION(IPv4Address("garbage"), std::invalid_argument);
  217. }
  218. MORDOR_UNITTEST(Address, parseIPv6Address)
  219. {
  220. try {
  221. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(IPv6Address("::")),
  222. "[::]:0");
  223. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(IPv6Address("::1", 443)),
  224. "[::1]:443");
  225. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(
  226. IPv6Address("2001:470::273:20c:0:0:5ddf")),
  227. "[2001:470::273:20c:0:0:5ddf]:0");
  228. MORDOR_TEST_ASSERT_EXCEPTION(IPv6Address("garbage"), std::invalid_argument);
  229. } catch (OperationNotSupportedException &) {
  230. throw TestSkippedException();
  231. }
  232. }
  233. // Test the address prefix length is 32 (IPv4), 128 (IPv6)
  234. MORDOR_UNITTEST(Address, fullPrefixLength)
  235. {
  236. IPv4Address ipv4("127.0.0.1");
  237. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(*ipv4.subnetMask(32)), "255.255.255.255:0");
  238. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(*ipv4.broadcastAddress(32)), "127.0.0.1:0");
  239. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(*ipv4.networkAddress(32)), "127.0.0.1:0");
  240. IPv6Address ipv6("2001:470::273:20c:0:0:5ddf");
  241. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(*ipv6.subnetMask(128)),
  242. "[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:0");
  243. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(*ipv6.broadcastAddress(128)),
  244. "[2001:470::273:20c:0:0:5ddf]:0");
  245. MORDOR_TEST_ASSERT_EQUAL(boost::lexical_cast<std::string>(*ipv6.networkAddress(128)),
  246. "[2001:470::273:20c:0:0:5ddf]:0");
  247. }
  248. static void cancelMe(Socket::ptr sock)
  249. {
  250. sock->cancelAccept();
  251. }
  252. MORDOR_UNITTEST(Socket, cancelAccept)
  253. {
  254. IOManager ioManager;
  255. Connection conns = establishConn(ioManager);
  256. // cancelMe will get run when this fiber yields because it would block
  257. ioManager.schedule(boost::bind(&cancelMe, conns.listen));
  258. MORDOR_TEST_ASSERT_EXCEPTION(conns.listen->accept(), OperationAbortedException);
  259. }
  260. MORDOR_UNITTEST(Socket, cancelSend)
  261. {
  262. IOManager ioManager;
  263. Connection conns = establishConn(ioManager);
  264. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  265. conns.connect->connect(conns.address);
  266. ioManager.dispatch();
  267. boost::scoped_array<char> array(new char[65536]);
  268. memset(array.get(), 1, 65536);
  269. struct iovec iov;
  270. iov.iov_base = array.get();
  271. iov.iov_len = 65536;
  272. conns.connect->cancelSend();
  273. MORDOR_TEST_ASSERT_EXCEPTION(while (conns.connect->send(iov.iov_base, 65536)) {}, OperationAbortedException);
  274. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->send(&iov, 1), OperationAbortedException);
  275. }
  276. MORDOR_UNITTEST(Socket, cancelReceive)
  277. {
  278. IOManager ioManager;
  279. Connection conns = establishConn(ioManager);
  280. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  281. conns.connect->connect(conns.address);
  282. ioManager.dispatch();
  283. char buf[3];
  284. memset(buf, 1, 3);
  285. struct iovec iov;
  286. iov.iov_base = buf;
  287. iov.iov_len = 3;
  288. conns.connect->cancelReceive();
  289. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->receive(iov.iov_base, 3), OperationAbortedException);
  290. MORDOR_TEST_ASSERT_EXCEPTION(conns.connect->receive(&iov, 1), OperationAbortedException);
  291. }
  292. MORDOR_UNITTEST(Socket, sendReceive)
  293. {
  294. IOManager ioManager;
  295. Connection conns = establishConn(ioManager);
  296. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  297. conns.connect->connect(conns.address);
  298. ioManager.dispatch();
  299. const char *sendbuf = "abcd";
  300. char receivebuf[5];
  301. memset(receivebuf, 0, 5);
  302. MORDOR_TEST_ASSERT_EQUAL(conns.connect->send(sendbuf, 1), 1u);
  303. MORDOR_TEST_ASSERT_EQUAL(conns.accept->receive(receivebuf, 1), 1u);
  304. MORDOR_TEST_ASSERT_EQUAL(receivebuf[0], 'a');
  305. receivebuf[0] = 0;
  306. iovec iov[2];
  307. iov[0].iov_base = (void *)&sendbuf[0];
  308. iov[1].iov_base = (void *)&sendbuf[2];
  309. iov[0].iov_len = 2;
  310. iov[1].iov_len = 2;
  311. MORDOR_TEST_ASSERT_EQUAL(conns.connect->send(iov, 2), 4u);
  312. iov[0].iov_base = &receivebuf[0];
  313. iov[1].iov_base = &receivebuf[2];
  314. MORDOR_TEST_ASSERT_EQUAL(conns.accept->receive(iov, 2), 4u);
  315. MORDOR_TEST_ASSERT_EQUAL(sendbuf, (const char *)receivebuf);
  316. }
  317. #ifndef WINDOWS
  318. MORDOR_UNITTEST(Socket, exceedIOVMAX)
  319. {
  320. IOManager ioManager;
  321. Connection conns = establishConn(ioManager);
  322. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  323. conns.connect->connect(conns.address);
  324. ioManager.dispatch();
  325. const char * buf = "abcd";
  326. size_t n = IOV_MAX + 1, len = 4;
  327. boost::shared_array<iovec> iovs(new iovec[n]);
  328. for (size_t i = 0 ; i < n; ++i) {
  329. iovs[i].iov_base = (void*)buf;
  330. iovs[i].iov_len = len;
  331. }
  332. size_t rc;
  333. try {
  334. rc = conns.connect->send(iovs.get(), n);
  335. } catch (...) {
  336. MORDOR_NOTREACHED();
  337. }
  338. MORDOR_TEST_ASSERT(rc <= IOV_MAX * len);
  339. MORDOR_TEST_ASSERT(rc >= 0);
  340. }
  341. #endif
  342. static void receiveFiber(Socket::ptr listen, size_t &sent, int &sequence)
  343. {
  344. MORDOR_TEST_ASSERT_EQUAL(++sequence, 1);
  345. Socket::ptr sock = listen->accept();
  346. MORDOR_TEST_ASSERT_EQUAL(++sequence, 3);
  347. char receivebuf[5];
  348. memset(receivebuf, 0, 5);
  349. Scheduler::yieldTo();
  350. MORDOR_TEST_ASSERT_EQUAL(++sequence, 5);
  351. MORDOR_TEST_ASSERT_EQUAL(sock->receive(receivebuf, 2), 2u);
  352. MORDOR_TEST_ASSERT_EQUAL(++sequence, 7);
  353. MORDOR_TEST_ASSERT_EQUAL((const char*)receivebuf, "ab");
  354. memset(receivebuf, 0, 5);
  355. iovec iov[2];
  356. iov[0].iov_base = &receivebuf[0];
  357. iov[1].iov_base = &receivebuf[2];
  358. iov[0].iov_len = 2;
  359. iov[1].iov_len = 2;
  360. Scheduler::yieldTo();
  361. MORDOR_TEST_ASSERT_EQUAL(++sequence, 9);
  362. MORDOR_TEST_ASSERT_EQUAL(sock->receive(iov, 2), 4u);
  363. MORDOR_TEST_ASSERT_EQUAL(++sequence, 11);
  364. MORDOR_TEST_ASSERT_EQUAL((const char*)receivebuf, "abcd");
  365. // Let the main fiber take control again until he "blocks"
  366. Scheduler::yieldTo();
  367. MORDOR_TEST_ASSERT_EQUAL(++sequence, 13);
  368. boost::shared_array<char> receivebuf2;
  369. if (sent > 0u) {
  370. receivebuf2.reset(new char[sent]);
  371. while (sent > 0u)
  372. sent -= sock->receive(receivebuf2.get(), sent);
  373. }
  374. // Let the main fiber update sent
  375. Scheduler::yieldTo();
  376. MORDOR_TEST_ASSERT_EQUAL(++sequence, 15);
  377. if (sent > 0u) {
  378. receivebuf2.reset(new char[sent]);
  379. while (sent > 0u)
  380. sent -= sock->receive(receivebuf2.get(), sent);
  381. }
  382. // Let the main fiber take control again until he "blocks"
  383. Scheduler::yieldTo();
  384. MORDOR_TEST_ASSERT_EQUAL(++sequence, 17);
  385. if (sent > 0u) {
  386. receivebuf2.reset(new char[std::max<size_t>(sent, 3u)]);
  387. iov[0].iov_base = &receivebuf2.get()[0];
  388. iov[1].iov_base = &receivebuf2.get()[2];
  389. while (sent > 0u) {
  390. size_t iovs = 2;
  391. if (sent > 2) {
  392. iov[1].iov_len = (iov_len_t)std::max<size_t>(sent, 3u) - 2;
  393. } else {
  394. iov[0].iov_len = (iov_len_t)sent;
  395. iovs = 1;
  396. }
  397. sent -= sock->receive(iov, iovs);
  398. }
  399. }
  400. // Let the main fiber update sent
  401. Scheduler::yieldTo();
  402. MORDOR_TEST_ASSERT_EQUAL(++sequence, 19);
  403. if (sent > 0u) {
  404. receivebuf2.reset(new char[std::max<size_t>(sent, 3u)]);
  405. iov[0].iov_base = &receivebuf2.get()[0];
  406. iov[1].iov_base = &receivebuf2.get()[2];
  407. iov[0].iov_len = 2;
  408. iov[1].iov_len = (iov_len_t)std::max<size_t>(sent, 3u) - 2;
  409. while (sent > 0u)
  410. sent -= sock->receive(iov, 2);
  411. }
  412. }
  413. // Disabled until frequently occuring deadlock on mac is investigated - SYNC-2070
  414. #ifndef OSX
  415. MORDOR_UNITTEST(Socket, sendReceiveForceAsync)
  416. {
  417. IOManager ioManager;
  418. Connection conns = establishConn(ioManager);
  419. int sequence = 0;
  420. size_t sent = 0;
  421. Fiber::ptr otherfiber(new Fiber(boost::bind(&receiveFiber, conns.listen,
  422. boost::ref(sent), boost::ref(sequence))));
  423. ioManager.schedule(otherfiber);
  424. // Wait for otherfiber to "block", and return control to us
  425. Scheduler::yield();
  426. MORDOR_TEST_ASSERT_EQUAL(++sequence, 2);
  427. // Unblock him, then wait for him to block again
  428. conns.connect->connect(conns.address);
  429. ioManager.dispatch();
  430. MORDOR_TEST_ASSERT_EQUAL(++sequence, 4);
  431. ioManager.schedule(otherfiber);
  432. Scheduler::yield();
  433. MORDOR_TEST_ASSERT_EQUAL(++sequence, 6);
  434. // Again
  435. const char *sendbuf = "abcd";
  436. MORDOR_TEST_ASSERT_EQUAL(conns.connect->send(sendbuf, 2), 2u);
  437. ioManager.dispatch();
  438. MORDOR_TEST_ASSERT_EQUAL(++sequence, 8);
  439. ioManager.schedule(otherfiber);
  440. Scheduler::yield();
  441. MORDOR_TEST_ASSERT_EQUAL(++sequence, 10);
  442. // And again
  443. iovec iov[2];
  444. iov[0].iov_base = (void *)&sendbuf[0];
  445. iov[1].iov_base = (void *)&sendbuf[2];
  446. iov[0].iov_len = 2;
  447. iov[1].iov_len = 2;
  448. MORDOR_TEST_ASSERT_EQUAL(conns.connect->send(iov, 2), 4u);
  449. ioManager.dispatch();
  450. MORDOR_TEST_ASSERT_EQUAL(++sequence, 12);
  451. char sendbuf2[65536];
  452. memset(sendbuf2, 1, 65536);
  453. // Keep sending until the other fiber said we blocked
  454. ioManager.schedule(otherfiber);
  455. while (true) {
  456. sent += conns.connect->send(sendbuf2, 65536);
  457. if (sequence == 13)
  458. break;
  459. }
  460. MORDOR_TEST_ASSERT_EQUAL(++sequence, 14);
  461. ioManager.schedule(otherfiber);
  462. ioManager.dispatch();
  463. MORDOR_TEST_ASSERT_EQUAL(++sequence, 16);
  464. MORDOR_TEST_ASSERT_EQUAL(sent, 0u);
  465. iov[0].iov_base = &sendbuf2[0];
  466. iov[1].iov_base = &sendbuf2[2];
  467. iov[1].iov_len = 65536 - 2;
  468. // Keep sending until the other fiber said we blocked
  469. ioManager.schedule(otherfiber);
  470. while (true) {
  471. sent += conns.connect->send(iov, 2);
  472. if (sequence == 17)
  473. break;
  474. }
  475. MORDOR_TEST_ASSERT_EQUAL(++sequence, 18);
  476. ioManager.schedule(otherfiber);
  477. ioManager.dispatch();
  478. MORDOR_TEST_ASSERT_EQUAL(++sequence, 20);
  479. }
  480. #endif
  481. static void closed(bool &remoteClosed)
  482. {
  483. remoteClosed = true;
  484. }
  485. MORDOR_UNITTEST(Socket, eventOnRemoteShutdown)
  486. {
  487. IOManager ioManager;
  488. Connection conns = establishConn(ioManager);
  489. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  490. conns.connect->connect(conns.address);
  491. ioManager.dispatch();
  492. bool remoteClosed = false;
  493. conns.accept->onRemoteClose(boost::bind(&closed, boost::ref(remoteClosed)));
  494. conns.connect->shutdown();
  495. ioManager.dispatch();
  496. MORDOR_TEST_ASSERT(remoteClosed);
  497. }
  498. MORDOR_UNITTEST(Socket, eventOnRemoteReset)
  499. {
  500. IOManager ioManager;
  501. Connection conns = establishConn(ioManager);
  502. ioManager.schedule(boost::bind(&acceptOne, boost::ref(conns)));
  503. conns.connect->connect(conns.address);
  504. ioManager.dispatch();
  505. bool remoteClosed = false;
  506. conns.accept->onRemoteClose(boost::bind(&closed, boost::ref(remoteClosed)));
  507. conns.connect.reset();
  508. ioManager.dispatch();
  509. MORDOR_TEST_ASSERT(remoteClosed);
  510. }