TestUDPSocket.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "TestCommon.h"
  5. #include "TestHarness.h"
  6. #include "nsIUDPSocket.h"
  7. #include "nsISocketTransportService.h"
  8. #include "nsISocketTransport.h"
  9. #include "nsIOutputStream.h"
  10. #include "nsIInputStream.h"
  11. #include "nsINetAddr.h"
  12. #include "nsIScriptSecurityManager.h"
  13. #include "nsITimer.h"
  14. #include "mozilla/net/DNS.h"
  15. #include "prerror.h"
  16. #define REQUEST 0x68656c6f
  17. #define RESPONSE 0x6f6c6568
  18. #define MULTICAST_TIMEOUT 2000
  19. #define EXPECT_SUCCESS(rv, ...) \
  20. PR_BEGIN_MACRO \
  21. if (NS_FAILED(rv)) { \
  22. fail(__VA_ARGS__); \
  23. return false; \
  24. } \
  25. PR_END_MACRO
  26. #define EXPECT_FAILURE(rv, ...) \
  27. PR_BEGIN_MACRO \
  28. if (NS_SUCCEEDED(rv)) { \
  29. fail(__VA_ARGS__); \
  30. return false; \
  31. } \
  32. PR_END_MACRO
  33. #define REQUIRE_EQUAL(a, b, ...) \
  34. PR_BEGIN_MACRO \
  35. if (a != b) { \
  36. fail(__VA_ARGS__); \
  37. return false; \
  38. } \
  39. PR_END_MACRO
  40. enum TestPhase {
  41. TEST_OUTPUT_STREAM,
  42. TEST_SEND_API,
  43. TEST_MULTICAST,
  44. TEST_NONE
  45. };
  46. static TestPhase phase = TEST_NONE;
  47. static bool CheckMessageContent(nsIUDPMessage *aMessage, uint32_t aExpectedContent)
  48. {
  49. nsCString data;
  50. aMessage->GetData(data);
  51. const char* buffer = data.get();
  52. uint32_t len = data.Length();
  53. FallibleTArray<uint8_t>& rawData = aMessage->GetDataAsTArray();
  54. uint32_t rawLen = rawData.Length();
  55. if (len != rawLen) {
  56. fail("Raw data length(%d) do not matches String data length(%d).", rawLen, len);
  57. return false;
  58. }
  59. for (uint32_t i = 0; i < len; i++) {
  60. if (buffer[i] != rawData[i]) {
  61. fail("Raw data(%s) do not matches String data(%s)", rawData.Elements() ,buffer);
  62. return false;
  63. }
  64. }
  65. uint32_t input = 0;
  66. for (uint32_t i = 0; i < len; i++) {
  67. input += buffer[i] << (8 * i);
  68. }
  69. if (len != sizeof(uint32_t) || input != aExpectedContent)
  70. {
  71. fail("Request 0x%x received, expected 0x%x", input, aExpectedContent);
  72. return false;
  73. } else {
  74. passed("Request 0x%x received as expected", input);
  75. return true;
  76. }
  77. }
  78. /*
  79. * UDPClientListener: listens for incomming UDP packets
  80. */
  81. class UDPClientListener : public nsIUDPSocketListener
  82. {
  83. protected:
  84. virtual ~UDPClientListener();
  85. public:
  86. NS_DECL_THREADSAFE_ISUPPORTS
  87. NS_DECL_NSIUDPSOCKETLISTENER
  88. nsresult mResult;
  89. };
  90. NS_IMPL_ISUPPORTS(UDPClientListener, nsIUDPSocketListener)
  91. UDPClientListener::~UDPClientListener() = default;
  92. NS_IMETHODIMP
  93. UDPClientListener::OnPacketReceived(nsIUDPSocket* socket, nsIUDPMessage* message)
  94. {
  95. mResult = NS_OK;
  96. uint16_t port;
  97. nsCString ip;
  98. nsCOMPtr<nsINetAddr> fromAddr;
  99. message->GetFromAddr(getter_AddRefs(fromAddr));
  100. fromAddr->GetPort(&port);
  101. fromAddr->GetAddress(ip);
  102. passed("Packet received on client from %s:%d", ip.get(), port);
  103. if (TEST_SEND_API == phase && CheckMessageContent(message, REQUEST)) {
  104. uint32_t count;
  105. const uint32_t data = RESPONSE;
  106. printf("*** Attempting to write response 0x%x to server by SendWithAddr...\n", RESPONSE);
  107. mResult = socket->SendWithAddr(fromAddr, (const uint8_t*)&data,
  108. sizeof(uint32_t), &count);
  109. if (mResult == NS_OK && count == sizeof(uint32_t)) {
  110. passed("Response written");
  111. } else {
  112. fail("Response written");
  113. }
  114. return NS_OK;
  115. } else if (TEST_OUTPUT_STREAM != phase || !CheckMessageContent(message, RESPONSE)) {
  116. mResult = NS_ERROR_FAILURE;
  117. }
  118. // Notify thread
  119. QuitPumpingEvents();
  120. return NS_OK;
  121. }
  122. NS_IMETHODIMP
  123. UDPClientListener::OnStopListening(nsIUDPSocket*, nsresult)
  124. {
  125. QuitPumpingEvents();
  126. return NS_OK;
  127. }
  128. /*
  129. * UDPServerListener: listens for incomming UDP packets
  130. */
  131. class UDPServerListener : public nsIUDPSocketListener
  132. {
  133. protected:
  134. virtual ~UDPServerListener();
  135. public:
  136. NS_DECL_THREADSAFE_ISUPPORTS
  137. NS_DECL_NSIUDPSOCKETLISTENER
  138. nsresult mResult;
  139. };
  140. NS_IMPL_ISUPPORTS(UDPServerListener, nsIUDPSocketListener)
  141. UDPServerListener::~UDPServerListener() = default;
  142. NS_IMETHODIMP
  143. UDPServerListener::OnPacketReceived(nsIUDPSocket* socket, nsIUDPMessage* message)
  144. {
  145. mResult = NS_OK;
  146. uint16_t port;
  147. nsCString ip;
  148. nsCOMPtr<nsINetAddr> fromAddr;
  149. message->GetFromAddr(getter_AddRefs(fromAddr));
  150. fromAddr->GetPort(&port);
  151. fromAddr->GetAddress(ip);
  152. passed("Packet received on server from %s:%d", ip.get(), port);
  153. if (TEST_OUTPUT_STREAM == phase && CheckMessageContent(message, REQUEST))
  154. {
  155. nsCOMPtr<nsIOutputStream> outstream;
  156. message->GetOutputStream(getter_AddRefs(outstream));
  157. uint32_t count;
  158. const uint32_t data = RESPONSE;
  159. printf("*** Attempting to write response 0x%x to client by OutputStream...\n", RESPONSE);
  160. mResult = outstream->Write((const char*)&data, sizeof(uint32_t), &count);
  161. if (mResult == NS_OK && count == sizeof(uint32_t)) {
  162. passed("Response written");
  163. } else {
  164. fail("Response written");
  165. }
  166. return NS_OK;
  167. } else if (TEST_MULTICAST == phase && CheckMessageContent(message, REQUEST)) {
  168. mResult = NS_OK;
  169. } else if (TEST_SEND_API != phase || !CheckMessageContent(message, RESPONSE)) {
  170. mResult = NS_ERROR_FAILURE;
  171. }
  172. // Notify thread
  173. QuitPumpingEvents();
  174. return NS_OK;
  175. }
  176. NS_IMETHODIMP
  177. UDPServerListener::OnStopListening(nsIUDPSocket*, nsresult)
  178. {
  179. QuitPumpingEvents();
  180. return NS_OK;
  181. }
  182. /**
  183. * Multicast timer callback: detects delivery failure
  184. */
  185. class MulticastTimerCallback : public nsITimerCallback
  186. {
  187. protected:
  188. virtual ~MulticastTimerCallback();
  189. public:
  190. NS_DECL_THREADSAFE_ISUPPORTS
  191. NS_DECL_NSITIMERCALLBACK
  192. nsresult mResult;
  193. };
  194. NS_IMPL_ISUPPORTS(MulticastTimerCallback, nsITimerCallback)
  195. MulticastTimerCallback::~MulticastTimerCallback() = default;
  196. NS_IMETHODIMP
  197. MulticastTimerCallback::Notify(nsITimer* timer)
  198. {
  199. if (TEST_MULTICAST != phase) {
  200. return NS_OK;
  201. }
  202. // Multicast ping failed
  203. printf("Multicast ping timeout expired\n");
  204. mResult = NS_ERROR_FAILURE;
  205. QuitPumpingEvents();
  206. return NS_OK;
  207. }
  208. /**** Main ****/
  209. int
  210. main(int32_t argc, char *argv[])
  211. {
  212. nsresult rv;
  213. ScopedXPCOM xpcom("UDP ServerSocket");
  214. if (xpcom.failed())
  215. return -1;
  216. // Create UDPSocket
  217. nsCOMPtr<nsIUDPSocket> server, client;
  218. server = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
  219. NS_ENSURE_SUCCESS(rv, -1);
  220. client = do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
  221. NS_ENSURE_SUCCESS(rv, -1);
  222. // Create UDPServerListener to process UDP packets
  223. RefPtr<UDPServerListener> serverListener = new UDPServerListener();
  224. nsCOMPtr<nsIScriptSecurityManager> secman =
  225. do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  226. NS_ENSURE_SUCCESS(rv, -1);
  227. nsCOMPtr<nsIPrincipal> systemPrincipal;
  228. rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
  229. NS_ENSURE_SUCCESS(rv, -1);
  230. // Bind server socket to 0.0.0.0
  231. rv = server->Init(0, false, systemPrincipal, true, 0);
  232. NS_ENSURE_SUCCESS(rv, -1);
  233. int32_t serverPort;
  234. server->GetPort(&serverPort);
  235. server->AsyncListen(serverListener);
  236. // Bind clinet on arbitrary port
  237. RefPtr<UDPClientListener> clientListener = new UDPClientListener();
  238. client->Init(0, false, systemPrincipal, true, 0);
  239. client->AsyncListen(clientListener);
  240. // Write data to server
  241. uint32_t count;
  242. const uint32_t data = REQUEST;
  243. phase = TEST_OUTPUT_STREAM;
  244. rv = client->Send(NS_LITERAL_CSTRING("127.0.0.1"), serverPort, (uint8_t*)&data, sizeof(uint32_t), &count);
  245. NS_ENSURE_SUCCESS(rv, -1);
  246. REQUIRE_EQUAL(count, sizeof(uint32_t), "Error");
  247. passed("Request written by Send");
  248. // Wait for server
  249. PumpEvents();
  250. NS_ENSURE_SUCCESS(serverListener->mResult, -1);
  251. // Read response from server
  252. NS_ENSURE_SUCCESS(clientListener->mResult, -1);
  253. mozilla::net::NetAddr clientAddr;
  254. rv = client->GetAddress(&clientAddr);
  255. NS_ENSURE_SUCCESS(rv, -1);
  256. // The client address is 0.0.0.0, but Windows won't receive packets there, so
  257. // use 127.0.0.1 explicitly
  258. clientAddr.inet.ip = PR_htonl(127 << 24 | 1);
  259. phase = TEST_SEND_API;
  260. rv = server->SendWithAddress(&clientAddr, (uint8_t*)&data, sizeof(uint32_t), &count);
  261. NS_ENSURE_SUCCESS(rv, -1);
  262. REQUIRE_EQUAL(count, sizeof(uint32_t), "Error");
  263. passed("Request written by SendWithAddress");
  264. // Wait for server
  265. PumpEvents();
  266. NS_ENSURE_SUCCESS(serverListener->mResult, -1);
  267. // Read response from server
  268. NS_ENSURE_SUCCESS(clientListener->mResult, -1);
  269. // Setup timer to detect multicast failure
  270. nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
  271. if (NS_WARN_IF(!timer)) {
  272. return -1;
  273. }
  274. RefPtr<MulticastTimerCallback> timerCb = new MulticastTimerCallback();
  275. // Join multicast group
  276. printf("Joining multicast group\n");
  277. phase = TEST_MULTICAST;
  278. mozilla::net::NetAddr multicastAddr;
  279. multicastAddr.inet.family = AF_INET;
  280. multicastAddr.inet.ip = PR_htonl(224 << 24 | 255);
  281. multicastAddr.inet.port = PR_htons(serverPort);
  282. rv = server->JoinMulticastAddr(multicastAddr, nullptr);
  283. if (NS_WARN_IF(NS_FAILED(rv))) {
  284. return -1;
  285. }
  286. // Send multicast ping
  287. timerCb->mResult = NS_OK;
  288. timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
  289. rv = client->SendWithAddress(&multicastAddr, (uint8_t*)&data, sizeof(uint32_t), &count);
  290. if (NS_WARN_IF(NS_FAILED(rv))) {
  291. return -1;
  292. }
  293. REQUIRE_EQUAL(count, sizeof(uint32_t), "Error");
  294. passed("Multicast ping written by SendWithAddress");
  295. // Wait for server to receive successfully
  296. PumpEvents();
  297. if (NS_WARN_IF(NS_FAILED(serverListener->mResult))) {
  298. return -1;
  299. }
  300. if (NS_WARN_IF(NS_FAILED(timerCb->mResult))) {
  301. return -1;
  302. }
  303. timer->Cancel();
  304. passed("Server received ping successfully");
  305. // Disable multicast loopback
  306. printf("Disable multicast loopback\n");
  307. client->SetMulticastLoopback(false);
  308. server->SetMulticastLoopback(false);
  309. // Send multicast ping
  310. timerCb->mResult = NS_OK;
  311. timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
  312. rv = client->SendWithAddress(&multicastAddr, (uint8_t*)&data, sizeof(uint32_t), &count);
  313. if (NS_WARN_IF(NS_FAILED(rv))) {
  314. return -1;
  315. }
  316. REQUIRE_EQUAL(count, sizeof(uint32_t), "Error");
  317. passed("Multicast ping written by SendWithAddress");
  318. // Wait for server to fail to receive
  319. PumpEvents();
  320. if (NS_WARN_IF(NS_SUCCEEDED(timerCb->mResult))) {
  321. return -1;
  322. }
  323. timer->Cancel();
  324. passed("Server failed to receive ping correctly");
  325. // Reset state
  326. client->SetMulticastLoopback(true);
  327. server->SetMulticastLoopback(true);
  328. // Change multicast interface
  329. printf("Changing multicast interface\n");
  330. mozilla::net::NetAddr loopbackAddr;
  331. loopbackAddr.inet.family = AF_INET;
  332. loopbackAddr.inet.ip = PR_htonl(INADDR_LOOPBACK);
  333. client->SetMulticastInterfaceAddr(loopbackAddr);
  334. // Send multicast ping
  335. timerCb->mResult = NS_OK;
  336. timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
  337. rv = client->SendWithAddress(&multicastAddr, (uint8_t*)&data, sizeof(uint32_t), &count);
  338. if (NS_WARN_IF(NS_FAILED(rv))) {
  339. return -1;
  340. }
  341. REQUIRE_EQUAL(count, sizeof(uint32_t), "Error");
  342. passed("Multicast ping written by SendWithAddress");
  343. // Wait for server to fail to receive
  344. PumpEvents();
  345. if (NS_WARN_IF(NS_SUCCEEDED(timerCb->mResult))) {
  346. return -1;
  347. }
  348. timer->Cancel();
  349. passed("Server failed to receive ping correctly");
  350. // Reset state
  351. mozilla::net::NetAddr anyAddr;
  352. anyAddr.inet.family = AF_INET;
  353. anyAddr.inet.ip = PR_htonl(INADDR_ANY);
  354. client->SetMulticastInterfaceAddr(anyAddr);
  355. // Leave multicast group
  356. printf("Leave multicast group\n");
  357. rv = server->LeaveMulticastAddr(multicastAddr, nullptr);
  358. if (NS_WARN_IF(NS_FAILED(rv))) {
  359. return -1;
  360. }
  361. // Send multicast ping
  362. timerCb->mResult = NS_OK;
  363. timer->InitWithCallback(timerCb, MULTICAST_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
  364. rv = client->SendWithAddress(&multicastAddr, (uint8_t*)&data, sizeof(uint32_t), &count);
  365. if (NS_WARN_IF(NS_FAILED(rv))) {
  366. return -1;
  367. }
  368. REQUIRE_EQUAL(count, sizeof(uint32_t), "Error");
  369. passed("Multicast ping written by SendWithAddress");
  370. // Wait for server to fail to receive
  371. PumpEvents();
  372. if (NS_WARN_IF(NS_SUCCEEDED(timerCb->mResult))) {
  373. return -1;
  374. }
  375. timer->Cancel();
  376. passed("Server failed to receive ping correctly");
  377. goto close;
  378. close:
  379. // Close server
  380. printf("*** Attempting to close server ...\n");
  381. server->Close();
  382. client->Close();
  383. PumpEvents();
  384. passed("Server closed");
  385. return 0; // failure is a non-zero return
  386. }