michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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: #include michael@0: #include michael@0: michael@0: #ifdef WIN32 michael@0: #include michael@0: #endif michael@0: michael@0: #include "nspr.h" michael@0: #include "nscore.h" michael@0: #include "nsISocketTransportService.h" michael@0: #include "nsIEventQueueService.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsITransport.h" michael@0: #include "nsIRequest.h" michael@0: #include "nsIStreamProvider.h" michael@0: #include "nsIStreamListener.h" michael@0: #include "nsIPipe.h" michael@0: #include "nsIOutputStream.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsCRT.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIByteArrayInputStream.h" michael@0: michael@0: #if defined(PR_LOGGING) michael@0: static PRLogModuleInfo *gTestSocketIOLog; michael@0: #define LOG(args) PR_LOG(gTestSocketIOLog, PR_LOG_DEBUG, args) michael@0: #else michael@0: #define LOG(args) michael@0: #endif michael@0: michael@0: static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID); michael@0: static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); michael@0: michael@0: static PRTime gElapsedTime; michael@0: static int gKeepRunning = 1; michael@0: static nsIEventQueue* gEventQ = nullptr; michael@0: michael@0: // michael@0: //---------------------------------------------------------------------------- michael@0: // Test Listener michael@0: //---------------------------------------------------------------------------- michael@0: // michael@0: michael@0: class TestListener : public nsIStreamListener michael@0: { michael@0: public: michael@0: TestListener() {} michael@0: virtual ~TestListener() {} michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSISTREAMLISTENER michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(TestListener, michael@0: nsIRequestObserver, michael@0: nsIStreamListener); michael@0: michael@0: NS_IMETHODIMP michael@0: TestListener::OnStartRequest(nsIRequest* request, nsISupports* context) michael@0: { michael@0: LOG(("TestListener::OnStartRequest\n")); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestListener::OnDataAvailable(nsIRequest* request, michael@0: nsISupports* context, michael@0: nsIInputStream *aIStream, michael@0: uint32_t aSourceOffset, michael@0: uint32_t aLength) michael@0: { michael@0: LOG(("TestListener::OnDataAvailable [offset=%u length=%u]\n", michael@0: aSourceOffset, aLength)); michael@0: char buf[1025]; michael@0: uint32_t amt; michael@0: while (1) { michael@0: aIStream->Read(buf, 1024, &amt); michael@0: if (amt == 0) michael@0: break; michael@0: buf[amt] = '\0'; michael@0: puts(buf); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestListener::OnStopRequest(nsIRequest* request, nsISupports* context, michael@0: nsresult aStatus) michael@0: { michael@0: LOG(("TestListener::OnStopRequest [aStatus=%x]\n", aStatus)); michael@0: gKeepRunning = 0; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: //---------------------------------------------------------------------------- michael@0: // Test Provider michael@0: //---------------------------------------------------------------------------- michael@0: // michael@0: michael@0: class TestProvider : public nsIStreamProvider michael@0: { michael@0: public: michael@0: TestProvider(char *data); michael@0: virtual ~TestProvider(); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSISTREAMPROVIDER michael@0: michael@0: protected: michael@0: nsCOMPtr mData; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(TestProvider, michael@0: nsIStreamProvider, michael@0: nsIRequestObserver) michael@0: michael@0: TestProvider::TestProvider(char *data) michael@0: { michael@0: NS_NewByteArrayInputStream(getter_AddRefs(mData), data, strlen(data)); michael@0: LOG(("Constructing TestProvider [this=%p]\n", this)); michael@0: } michael@0: michael@0: TestProvider::~TestProvider() michael@0: { michael@0: LOG(("Destroying TestProvider [this=%p]\n", this)); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestProvider::OnStartRequest(nsIRequest* request, nsISupports* context) michael@0: { michael@0: LOG(("TestProvider::OnStartRequest [this=%p]\n", this)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestProvider::OnStopRequest(nsIRequest* request, nsISupports* context, michael@0: nsresult aStatus) michael@0: { michael@0: LOG(("TestProvider::OnStopRequest [status=%x]\n", aStatus)); michael@0: michael@0: nsCOMPtr listener = do_QueryInterface(new TestListener()); michael@0: michael@0: if (NS_SUCCEEDED(aStatus)) { michael@0: nsCOMPtr treq = do_QueryInterface(request); michael@0: nsCOMPtr transport; michael@0: treq->GetTransport(getter_AddRefs(transport)); michael@0: if (transport) { michael@0: nsCOMPtr readRequest; michael@0: transport->AsyncRead(listener, nullptr, 0, 0, 0, getter_AddRefs(readRequest)); michael@0: } michael@0: } else michael@0: gKeepRunning = 0; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: TestProvider::OnDataWritable(nsIRequest *request, nsISupports *context, michael@0: nsIOutputStream *output, uint32_t offset, uint32_t count) michael@0: { michael@0: LOG(("TestProvider::OnDataWritable [offset=%u, count=%u]\n", offset, count)); michael@0: uint32_t writeCount; michael@0: nsresult rv = output->WriteFrom(mData, count, &writeCount); michael@0: // Zero bytes written on success indicates EOF michael@0: if (NS_SUCCEEDED(rv) && (writeCount == 0)) michael@0: return NS_BASE_STREAM_CLOSED; michael@0: return rv; michael@0: } michael@0: michael@0: // michael@0: //---------------------------------------------------------------------------- michael@0: // Synchronous IO michael@0: //---------------------------------------------------------------------------- michael@0: // michael@0: nsresult michael@0: WriteRequest(nsIOutputStream *os, const char *request) michael@0: { michael@0: LOG(("WriteRequest [request=%s]\n", request)); michael@0: uint32_t n; michael@0: return os->Write(request, strlen(request), &n); michael@0: } michael@0: michael@0: nsresult michael@0: ReadResponse(nsIInputStream *is) michael@0: { michael@0: uint32_t bytesRead; michael@0: char buf[2048]; michael@0: do { michael@0: is->Read(buf, sizeof(buf), &bytesRead); michael@0: if (bytesRead > 0) michael@0: fwrite(buf, 1, bytesRead, stdout); michael@0: } while (bytesRead > 0); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // michael@0: //---------------------------------------------------------------------------- michael@0: // Startup... michael@0: //---------------------------------------------------------------------------- michael@0: // michael@0: michael@0: void michael@0: sighandler(int sig) michael@0: { michael@0: LOG(("got signal: %d\n", sig)); michael@0: NS_BREAK(); michael@0: } michael@0: michael@0: void michael@0: usage(char **argv) michael@0: { michael@0: printf("usage: %s [-sync] \n", argv[0]); michael@0: exit(1); michael@0: } michael@0: michael@0: int michael@0: main(int argc, char* argv[]) michael@0: { michael@0: nsresult rv; michael@0: michael@0: signal(SIGSEGV, sighandler); michael@0: michael@0: #if defined(PR_LOGGING) michael@0: gTestSocketIOLog = PR_NewLogModule("TestSocketIO"); michael@0: #endif michael@0: michael@0: if (argc < 3) michael@0: usage(argv); michael@0: michael@0: int i=0; michael@0: bool sync = false; michael@0: if (nsCRT::strcasecmp(argv[1], "-sync") == 0) { michael@0: if (argc < 4) michael@0: usage(argv); michael@0: sync = true; michael@0: i = 1; michael@0: } michael@0: michael@0: char *hostName = argv[1+i]; michael@0: char *fileName = argv[2+i]; michael@0: int port = 80; michael@0: michael@0: // Create the Event Queue for this thread... michael@0: nsCOMPtr eventQService = michael@0: do_GetService(kEventQueueServiceCID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("failed to create: event queue service!"); michael@0: return rv; michael@0: } michael@0: michael@0: rv = eventQService->CreateMonitoredThreadEventQueue(); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("failed to create: thread event queue!"); michael@0: return rv; michael@0: } michael@0: michael@0: eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, &gEventQ); michael@0: michael@0: // Create the Socket transport service... michael@0: nsCOMPtr sts = michael@0: do_GetService(kSocketTransportServiceCID, &rv); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("failed to create: socket transport service!"); michael@0: return rv; michael@0: } michael@0: michael@0: char *buffer = PR_smprintf("GET %s HTTP/1.1" CRLF michael@0: "host: %s" CRLF michael@0: "user-agent: Mozilla/5.0 (X11; N; Linux 2.2.16-22smp i686; en-US; m18) Gecko/20001220" CRLF michael@0: "accept: */*" CRLF michael@0: "accept-language: en" CRLF michael@0: "accept-encoding: gzip,deflate,compress,identity" CRLF michael@0: "keep-alive: 300" CRLF michael@0: "connection: keep-alive" CRLF michael@0: CRLF, michael@0: fileName, hostName); michael@0: LOG(("Request [\n%s]\n", buffer)); michael@0: michael@0: // Create the socket transport... michael@0: nsCOMPtr transport; michael@0: rv = sts->CreateTransport(hostName, port, nullptr, 0, 0, getter_AddRefs(transport)); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("failed to create: socket transport!"); michael@0: return rv; michael@0: } michael@0: michael@0: gElapsedTime = PR_Now(); michael@0: michael@0: if (!sync) { michael@0: nsCOMPtr request; michael@0: rv = transport->AsyncWrite(new TestProvider(buffer), nullptr, 0, 0, 0, getter_AddRefs(request)); michael@0: if (NS_FAILED(rv)) { michael@0: NS_WARNING("failed calling: AsyncWrite!"); michael@0: return rv; michael@0: } michael@0: michael@0: // Enter the message pump to allow the URL load to proceed. michael@0: while ( gKeepRunning ) { michael@0: PLEvent *gEvent; michael@0: gEventQ->WaitForEvent(&gEvent); michael@0: gEventQ->HandleEvent(gEvent); michael@0: } michael@0: } michael@0: else { michael@0: // synchronous write michael@0: { michael@0: nsCOMPtr os; michael@0: rv = transport->OpenOutputStream(0, 0, 0, getter_AddRefs(os)); michael@0: if (NS_FAILED(rv)) { michael@0: LOG(("OpenOutputStream failed [rv=%x]\n", rv)); michael@0: return rv; michael@0: } michael@0: rv = WriteRequest(os, buffer); michael@0: if (NS_FAILED(rv)) { michael@0: LOG(("WriteRequest failed [rv=%x]\n", rv)); michael@0: return rv; michael@0: } michael@0: } michael@0: // synchronous read michael@0: { michael@0: nsCOMPtr is; michael@0: rv = transport->OpenInputStream(0, 0, 0, getter_AddRefs(is)); michael@0: if (NS_FAILED(rv)) { michael@0: LOG(("OpenInputStream failed [rv=%x]\n", rv)); michael@0: return rv; michael@0: } michael@0: rv = ReadResponse(is); michael@0: if (NS_FAILED(rv)) { michael@0: LOG(("ReadResponse failed [rv=%x]\n", rv)); michael@0: return rv; michael@0: } michael@0: } michael@0: } michael@0: michael@0: PRTime endTime; michael@0: endTime = PR_Now(); michael@0: LOG(("Elapsed time: %d\n", (int32_t)(endTime/1000UL - gElapsedTime/1000UL))); michael@0: michael@0: sts->Shutdown(); michael@0: return 0; michael@0: } michael@0: