TestBind.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 "nsISocketTransportService.h"
  7. #include "nsISocketTransport.h"
  8. #include "nsIServerSocket.h"
  9. #include "nsIAsyncInputStream.h"
  10. #include "nsINetAddr.h"
  11. #include "mozilla/net/DNS.h"
  12. #include "prerror.h"
  13. using namespace mozilla::net;
  14. using namespace mozilla;
  15. class ServerListener: public nsIServerSocketListener
  16. {
  17. public:
  18. NS_DECL_ISUPPORTS
  19. NS_DECL_NSISERVERSOCKETLISTENER
  20. ServerListener();
  21. // Port that is got from server side will be store here.
  22. uint32_t mClientPort;
  23. bool mFailed;
  24. private:
  25. virtual ~ServerListener();
  26. };
  27. NS_IMPL_ISUPPORTS(ServerListener, nsIServerSocketListener)
  28. ServerListener::ServerListener()
  29. : mClientPort(-1)
  30. , mFailed(false)
  31. {
  32. }
  33. ServerListener::~ServerListener() = default;
  34. NS_IMETHODIMP
  35. ServerListener::OnSocketAccepted(nsIServerSocket *aServ,
  36. nsISocketTransport *aTransport)
  37. {
  38. // Run on STS thread.
  39. NetAddr peerAddr;
  40. nsresult rv = aTransport->GetPeerAddr(&peerAddr);
  41. if (NS_FAILED(rv)) {
  42. mFailed = true;
  43. fail("Server: not able to get peer address.");
  44. QuitPumpingEvents();
  45. return NS_OK;
  46. }
  47. mClientPort = PR_ntohs(peerAddr.inet.port);
  48. passed("Server: received connection");
  49. QuitPumpingEvents();
  50. return NS_OK;
  51. }
  52. NS_IMETHODIMP
  53. ServerListener::OnStopListening(nsIServerSocket *aServ,
  54. nsresult aStatus)
  55. {
  56. return NS_OK;
  57. }
  58. class ClientInputCallback : public nsIInputStreamCallback
  59. {
  60. public:
  61. NS_DECL_THREADSAFE_ISUPPORTS
  62. NS_DECL_NSIINPUTSTREAMCALLBACK
  63. ClientInputCallback();
  64. bool mFailed;
  65. private:
  66. virtual ~ClientInputCallback();
  67. };
  68. NS_IMPL_ISUPPORTS(ClientInputCallback, nsIInputStreamCallback)
  69. ClientInputCallback::ClientInputCallback()
  70. : mFailed(false)
  71. {
  72. }
  73. ClientInputCallback::~ClientInputCallback() = default;
  74. NS_IMETHODIMP
  75. ClientInputCallback::OnInputStreamReady(nsIAsyncInputStream *aStream)
  76. {
  77. // Server doesn't send. That means if we are here, we probably have run into
  78. // an error.
  79. uint64_t avail;
  80. nsresult rv = aStream->Available(&avail);
  81. if (NS_FAILED(rv)) {
  82. mFailed = true;
  83. }
  84. QuitPumpingEvents();
  85. return NS_OK;
  86. }
  87. int
  88. main(int32_t argc, char *argv[])
  89. {
  90. ScopedXPCOM xpcom("SocketTransport");
  91. if (xpcom.failed()) {
  92. fail("Unable to initalize XPCOM.");
  93. return -1;
  94. }
  95. //
  96. // Server side.
  97. //
  98. nsCOMPtr<nsIServerSocket> server = do_CreateInstance("@mozilla.org/network/server-socket;1");
  99. if (!server) {
  100. fail("Failed to create server socket.");
  101. return -1;
  102. }
  103. nsresult rv = server->Init(-1, true, -1);
  104. if (NS_FAILED(rv)) {
  105. fail("Failed to initialize server.");
  106. return -1;
  107. }
  108. int32_t serverPort;
  109. rv = server->GetPort(&serverPort);
  110. if (NS_FAILED(rv)) {
  111. fail("Unable to get server port.");
  112. return -1;
  113. }
  114. // Listening.
  115. RefPtr<ServerListener> serverListener = new ServerListener();
  116. rv = server->AsyncListen(serverListener);
  117. if (NS_FAILED(rv)) {
  118. fail("Server fail to start listening.");
  119. return -1;
  120. }
  121. //
  122. // Client side
  123. //
  124. uint32_t bindingPort = 20000;
  125. nsCOMPtr<nsISocketTransportService> sts =
  126. do_GetService("@mozilla.org/network/socket-transport-service;1", &rv);
  127. if (NS_FAILED(rv)) {
  128. fail("Unable to get socket transport service.");
  129. return -1;
  130. }
  131. for (int32_t tried = 0; tried < 100; tried++) {
  132. nsCOMPtr<nsISocketTransport> client;
  133. rv = sts->CreateTransport(nullptr, 0, NS_LITERAL_CSTRING("127.0.0.1"),
  134. serverPort, nullptr, getter_AddRefs(client));
  135. if (NS_FAILED(rv)) {
  136. fail("Unable to create transport.");
  137. return -1;
  138. }
  139. // Bind to a port. It's possible that we are binding to a port that is
  140. // currently in use. If we failed to bind, we try next port.
  141. NetAddr bindingAddr;
  142. bindingAddr.inet.family = AF_INET;
  143. bindingAddr.inet.ip = 0;
  144. bindingAddr.inet.port = PR_htons(bindingPort);
  145. rv = client->Bind(&bindingAddr);
  146. if (NS_FAILED(rv)) {
  147. fail("Unable to bind a port.");
  148. return -1;
  149. }
  150. // Open IO streams, to make client SocketTransport connect to server.
  151. RefPtr<ClientInputCallback> clientCallback = new ClientInputCallback();
  152. nsCOMPtr<nsIInputStream> inputStream;
  153. rv = client->OpenInputStream(nsITransport::OPEN_UNBUFFERED,
  154. 0, 0, getter_AddRefs(inputStream));
  155. if (NS_FAILED(rv)) {
  156. fail("Failed to open an input stream.");
  157. return -1;
  158. }
  159. nsCOMPtr<nsIAsyncInputStream> asyncInputStream = do_QueryInterface(inputStream);
  160. rv = asyncInputStream->AsyncWait(clientCallback, 0, 0, nullptr);
  161. // Wait for server's response or callback of input stream.
  162. PumpEvents();
  163. if (clientCallback->mFailed) {
  164. // if client received error, we likely have bound a port that is in use.
  165. // we can try another port.
  166. bindingPort++;
  167. } else {
  168. // We are unlocked by server side, leave the loop and check result.
  169. break;
  170. }
  171. }
  172. if (serverListener->mFailed) {
  173. fail("Server failure.");
  174. return -1;
  175. }
  176. if (serverListener->mClientPort != bindingPort) {
  177. fail("Port that server got doesn't match what we are expecting.");
  178. return -1;
  179. }
  180. passed("Port matched");
  181. return 0;
  182. }