michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "TestCommon.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsPISocketTransportService.h" michael@0: #include "nsISocketTransport.h" michael@0: #include "nsIAsyncInputStream.h" michael@0: #include "nsIAsyncOutputStream.h" michael@0: #include "nsIProgressEventSink.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIRequest.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsMemory.h" michael@0: #include "nsStringAPI.h" michael@0: #include "nsIDNSService.h" michael@0: #include "nsIFileStreams.h" michael@0: #include "nsIStreamListener.h" michael@0: #include "nsIFile.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsAutoLock.h" michael@0: #include "prlog.h" michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #if defined(PR_LOGGING) michael@0: // michael@0: // set NSPR_LOG_MODULES=Test:5 michael@0: // michael@0: static PRLogModuleInfo *gTestLog = nullptr; michael@0: #endif michael@0: #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: class MyHandler : public nsIOutputStreamCallback michael@0: , public nsIInputStreamCallback michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: MyHandler(const char *path, michael@0: nsIAsyncInputStream *in, michael@0: nsIAsyncOutputStream *out) michael@0: : mInput(in) michael@0: , mOutput(out) michael@0: , mWriteOffset(0) michael@0: { michael@0: mBuf.Assign(NS_LITERAL_CSTRING("GET ")); michael@0: mBuf.Append(path); michael@0: mBuf.Append(NS_LITERAL_CSTRING(" HTTP/1.0\r\n\r\n")); michael@0: } michael@0: virtual ~MyHandler() {} michael@0: michael@0: // called on any thread michael@0: NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *out) michael@0: { michael@0: LOG(("OnOutputStreamReady\n")); michael@0: michael@0: nsresult rv; michael@0: uint32_t n, count = mBuf.Length() - mWriteOffset; michael@0: michael@0: rv = out->Write(mBuf.get() + mWriteOffset, count, &n); michael@0: michael@0: LOG((" write returned [rv=%x count=%u]\n", rv, n)); michael@0: michael@0: if (NS_FAILED(rv) || (n == 0)) { michael@0: if (rv != NS_BASE_STREAM_WOULD_BLOCK) { michael@0: LOG((" done writing; starting to read\n")); michael@0: mInput->AsyncWait(this, 0, 0, nullptr); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: mWriteOffset += n; michael@0: michael@0: return out->AsyncWait(this, 0, 0, nullptr); michael@0: } michael@0: michael@0: // called on any thread michael@0: NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *in) michael@0: { michael@0: LOG(("OnInputStreamReady\n")); michael@0: michael@0: nsresult rv; michael@0: uint32_t n; michael@0: char buf[500]; michael@0: michael@0: rv = in->Read(buf, sizeof(buf), &n); michael@0: michael@0: LOG((" read returned [rv=%x count=%u]\n", rv, n)); michael@0: michael@0: if (NS_FAILED(rv) || (n == 0)) { michael@0: if (rv != NS_BASE_STREAM_WOULD_BLOCK) { michael@0: QuitPumpingEvents(); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: return in->AsyncWait(this, 0, 0, nullptr); michael@0: } michael@0: michael@0: private: michael@0: nsCOMPtr mInput; michael@0: nsCOMPtr mOutput; michael@0: nsCString mBuf; michael@0: uint32_t mWriteOffset; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(MyHandler, michael@0: nsIOutputStreamCallback, michael@0: nsIInputStreamCallback) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * create transport, open streams, and close michael@0: */ michael@0: static nsresult michael@0: RunCloseTest(nsISocketTransportService *sts, michael@0: const char *host, int port, michael@0: uint32_t inFlags, uint32_t outFlags) michael@0: { michael@0: nsresult rv; michael@0: michael@0: LOG(("RunCloseTest\n")); michael@0: michael@0: nsCOMPtr transport; michael@0: rv = sts->CreateTransport(nullptr, 0, michael@0: nsDependentCString(host), port, nullptr, michael@0: getter_AddRefs(transport)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr in; michael@0: rv = transport->OpenInputStream(inFlags, 0, 0, getter_AddRefs(in)); michael@0: nsCOMPtr asyncIn = do_QueryInterface(in, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr out; michael@0: rv = transport->OpenOutputStream(outFlags, 0, 0, getter_AddRefs(out)); michael@0: nsCOMPtr asyncOut = do_QueryInterface(out, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: LOG(("waiting 1 second before closing transport and streams...\n")); michael@0: PR_Sleep(PR_SecondsToInterval(1)); michael@0: michael@0: // let nsCOMPtr destructors close everything... michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * asynchronously read socket stream michael@0: */ michael@0: static nsresult michael@0: RunTest(nsISocketTransportService *sts, michael@0: const char *host, int port, const char *path, michael@0: uint32_t inFlags, uint32_t outFlags) michael@0: { michael@0: nsresult rv; michael@0: michael@0: LOG(("RunTest\n")); michael@0: michael@0: nsCOMPtr transport; michael@0: rv = sts->CreateTransport(nullptr, 0, michael@0: nsDependentCString(host), port, nullptr, michael@0: getter_AddRefs(transport)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr in; michael@0: rv = transport->OpenInputStream(inFlags, 0, 0, getter_AddRefs(in)); michael@0: nsCOMPtr asyncIn = do_QueryInterface(in, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr out; michael@0: rv = transport->OpenOutputStream(outFlags, 0, 0, getter_AddRefs(out)); michael@0: nsCOMPtr asyncOut = do_QueryInterface(out, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: MyHandler *handler = new MyHandler(path, asyncIn, asyncOut); michael@0: if (handler == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(handler); michael@0: michael@0: rv = asyncOut->AsyncWait(handler, 0, 0, nullptr); michael@0: michael@0: if (NS_SUCCEEDED(rv)) michael@0: PumpEvents(); michael@0: michael@0: NS_RELEASE(handler); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: int michael@0: main(int argc, char* argv[]) michael@0: { michael@0: if (test_common_init(&argc, &argv) != 0) michael@0: return -1; michael@0: michael@0: nsresult rv; michael@0: michael@0: if (argc < 4) { michael@0: printf("usage: TestSocketTransport \n"); michael@0: return -1; michael@0: } michael@0: michael@0: { michael@0: nsCOMPtr servMan; michael@0: NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); michael@0: nsCOMPtr registrar = do_QueryInterface(servMan); michael@0: NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); michael@0: if (registrar) michael@0: registrar->AutoRegister(nullptr); michael@0: michael@0: #if defined(PR_LOGGING) michael@0: gTestLog = PR_NewLogModule("Test"); michael@0: #endif michael@0: michael@0: // Make sure the DNS service is initialized on the main thread michael@0: nsCOMPtr dns = michael@0: do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr sts = michael@0: do_GetService(kSocketTransportServiceCID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: LOG(("phase 1 tests...\n")); michael@0: michael@0: LOG(("flags = { OPEN_UNBUFFERED, OPEN_UNBUFFERED }\n")); michael@0: rv = RunCloseTest(sts, argv[1], atoi(argv[2]), michael@0: nsITransport::OPEN_UNBUFFERED, michael@0: nsITransport::OPEN_UNBUFFERED); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); michael@0: michael@0: LOG(("flags = { OPEN_BUFFERED, OPEN_UNBUFFERED }\n")); michael@0: rv = RunCloseTest(sts, argv[1], atoi(argv[2]), michael@0: 0 /* nsITransport::OPEN_BUFFERED */, michael@0: nsITransport::OPEN_UNBUFFERED); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); michael@0: michael@0: LOG(("flags = { OPEN_UNBUFFERED, OPEN_BUFFERED }\n")); michael@0: rv = RunCloseTest(sts, argv[1], atoi(argv[2]), michael@0: nsITransport::OPEN_UNBUFFERED, michael@0: 0 /*nsITransport::OPEN_BUFFERED */); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); michael@0: michael@0: LOG(("flags = { OPEN_BUFFERED, OPEN_BUFFERED }\n")); michael@0: rv = RunCloseTest(sts, argv[1], atoi(argv[2]), michael@0: 0 /*nsITransport::OPEN_BUFFERED */, michael@0: 0 /*nsITransport::OPEN_BUFFERED */); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunCloseTest failed"); michael@0: michael@0: LOG(("calling Shutdown on socket transport service:\n")); michael@0: sts->Shutdown(); michael@0: michael@0: LOG(("calling Init on socket transport service:\n")); michael@0: sts->Init(); michael@0: michael@0: LOG(("phase 2 tests...\n")); michael@0: michael@0: LOG(("flags = { OPEN_UNBUFFERED, OPEN_UNBUFFERED }\n")); michael@0: rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], michael@0: nsITransport::OPEN_UNBUFFERED, michael@0: nsITransport::OPEN_UNBUFFERED); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); michael@0: michael@0: LOG(("flags = { OPEN_BUFFERED, OPEN_UNBUFFERED }\n")); michael@0: rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], michael@0: 0 /* nsITransport::OPEN_BUFFERED */, michael@0: nsITransport::OPEN_UNBUFFERED); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); michael@0: michael@0: LOG(("flags = { OPEN_UNBUFFERED, OPEN_BUFFERED }\n")); michael@0: rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], michael@0: nsITransport::OPEN_UNBUFFERED, michael@0: 0 /*nsITransport::OPEN_BUFFERED */); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); michael@0: michael@0: LOG(("flags = { OPEN_BUFFERED, OPEN_BUFFERED }\n")); michael@0: rv = RunTest(sts, argv[1], atoi(argv[2]), argv[3], michael@0: 0 /*nsITransport::OPEN_BUFFERED */, michael@0: 0 /*nsITransport::OPEN_BUFFERED */); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); michael@0: michael@0: LOG(("waiting 1 second before calling Shutdown...\n")); michael@0: PR_Sleep(PR_SecondsToInterval(1)); michael@0: michael@0: LOG(("calling Shutdown on socket transport service:\n")); michael@0: sts->Shutdown(); michael@0: michael@0: // give background threads a chance to finish whatever work they may michael@0: // be doing. michael@0: LOG(("waiting 1 second before exiting...\n")); michael@0: PR_Sleep(PR_SecondsToInterval(1)); michael@0: } // this scopes the nsCOMPtrs michael@0: // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM michael@0: rv = NS_ShutdownXPCOM(nullptr); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); michael@0: return 0; michael@0: }