Back to index

enigmail  1.4.3
nsIPCBuffer.cpp
Go to the documentation of this file.
00001 /*
00002  * The contents of this file are subject to the Mozilla Public
00003  * License Version 1.1 (the "MPL"); you may not use this file
00004  * except in compliance with the MPL. You may obtain a copy of
00005  * the MPL at http://www.mozilla.org/MPL/
00006  *
00007  * Software distributed under the MPL is distributed on an "AS
00008  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
00009  * implied. See the MPL for the specific language governing
00010  * rights and limitations under the MPL.
00011  *
00012  * The Original Code is protoZilla.
00013  *
00014  * The Initial Developer of the Original Code is Ramalingam Saravanan.
00015  * Portions created by Ramalingam Saravanan <svn@xmlterm.org> are
00016  * Copyright (C) 2000 Ramalingam Saravanan. All Rights Reserved.
00017  *
00018  * Contributor(s):
00019  * Patrick Brunschwig <patrick@mozilla-enigmail.org>
00020  *
00021  * Alternatively, the contents of this file may be used under the
00022  * terms of the GNU General Public License (the "GPL"), in which case
00023  * the provisions of the GPL are applicable instead of
00024  * those above. If you wish to allow use of your version of this
00025  * file only under the terms of the GPL and not to allow
00026  * others to use your version of this file under the MPL, indicate
00027  * your decision by deleting the provisions above and replace them
00028  * with the notice and other provisions required by the GPL.
00029  * If you do not delete the provisions above, a recipient
00030  * may use your version of this file under either the MPL or the
00031  * GPL.
00032  */
00033 
00034 // Logging of debug output
00035 // The following define statement should occur before any include statements
00036 #define FORCE_PR_LOG       /* Allow logging even in release build */
00037 
00038 #include "ipc.h"
00039 #include "prlog.h"
00040 #include "nsCOMPtr.h"
00041 #include "mozilla/Mutex.h"
00042 #include "nsIInputStream.h"
00043 #include "nsIThread.h"
00044 #include "nsIHttpChannel.h"
00045 #include "nsNetUtil.h"
00046 #include "nsDirectoryServiceUtils.h"
00047 #include "nsDirectoryServiceDefs.h"
00048 #include "nsNetCID.h"
00049 #include "nsStringGlue.h"
00050 
00051 #include "nsIPCBuffer.h"
00052 
00053 #ifdef PR_LOGGING
00054 PRLogModuleInfo* gIPCBufferLog = NULL;
00055 #endif
00056 
00057 #define ERROR_LOG(args)    PR_LOG(gIPCBufferLog,PR_LOG_ERROR,args)
00058 #define WARNING_LOG(args)  PR_LOG(gIPCBufferLog,PR_LOG_WARNING,args)
00059 #define DEBUG_LOG(args)    PR_LOG(gIPCBufferLog,PR_LOG_DEBUG,args)
00060 
00061 #define NS_PIPE_CONSOLE_BUFFER_SIZE   (1024)
00062 
00063 static const PRUint32 kCharMax = NS_PIPE_CONSOLE_BUFFER_SIZE;
00064 
00066 
00067 // nsIPCBuffer implementation
00068 
00069 using namespace mozilla;
00070 
00071 // nsISupports implementation
00072 NS_IMPL_THREADSAFE_ISUPPORTS6(nsIPCBuffer,
00073                               nsIRequestObserver,
00074                               nsIStreamListener,
00075                               nsIPipeListener,
00076                               nsIIPCBuffer,
00077                               nsIInputStream,
00078                               nsIRunnable)
00079 
00080 
00081 // nsIPCBuffer implementation
00082 nsIPCBuffer::nsIPCBuffer() :
00083     mFinalized(PR_FALSE),
00084     mInitialized(PR_FALSE),
00085     mThreadJoined(PR_FALSE),
00086     mOverflowed(PR_FALSE),
00087     mOverflowFile(PR_FALSE),
00088 
00089     mRequestStarted(PR_FALSE),
00090     mRequestStopped(PR_FALSE),
00091 
00092     mLock("nsIPCBuffer.lock"),
00093     mMaxBytes(0),
00094     mByteCount(0),
00095     mStreamOffset(0),
00096 
00097     mByteBuf(""),
00098 
00099     mPipeWrite(IPC_NULL_HANDLE),
00100     mPipeRead(IPC_NULL_HANDLE),
00101 
00102     mTempFile(nsnull),
00103     mTempOutStream(nsnull),
00104     mTempInStream(nsnull),
00105 
00106     mPipeThread(nsnull),
00107     mObserver(nsnull),
00108     mObserverContext(nsnull)
00109 {
00110 #ifdef PR_LOGGING
00111   if (!gIPCBufferLog) {
00112     gIPCBufferLog = PR_NewLogModule("nsIPCBuffer");
00113   }
00114 #endif
00115 
00116 #ifdef FORCE_PR_LOG
00117   nsCOMPtr<nsIThread> myThread;
00118   IPC_GET_THREAD(myThread);
00119   DEBUG_LOG(("nsIPCBuffer:: <<<<<<<<< CTOR(%p): myThread=%p\n",
00120          this, myThread.get()));
00121 #endif
00122 }
00123 
00124 
00125 nsIPCBuffer::~nsIPCBuffer()
00126 {
00127 #ifdef FORCE_PR_LOG
00128   nsCOMPtr<nsIThread> myThread;
00129   IPC_GET_THREAD(myThread);
00130   DEBUG_LOG(("nsIPCBuffer:: >>>>>>>>> DTOR(%p): myThread=%p\n",
00131          this, myThread.get()));
00132 #endif
00133 
00134   Finalize(PR_TRUE);
00135 
00136 }
00137 
00138 // forward declaration
00139 PRStatus IPC_CreateInheritablePipe(PRFileDesc* *readPipe,
00140                                        PRFileDesc* *writePipe,
00141                                        IPCBool readInherit,
00142                                        IPCBool writeInherit);
00143 
00145 // nsIPCBuffer methods:
00147 
00148 nsresult
00149 nsIPCBuffer::Finalize(IPCBool destructor)
00150 {
00151   DEBUG_LOG(("nsIPCBuffer::Finalize: \n"));
00152 
00153   if (mFinalized)
00154     return NS_OK;
00155 
00156   mFinalized = PR_TRUE;
00157 
00158   nsCOMPtr<nsIIPCBuffer> self;
00159   if (!destructor) {
00160     // Hold a reference to ourselves to prevent our DTOR from being called
00161     // while finalizing. Automatically released upon returning.
00162     self = this;
00163   }
00164 
00165   // Close write pipe
00166   if (mPipeWrite) {
00167     IPC_Close(mPipeWrite);
00168     mPipeWrite = IPC_NULL_HANDLE;
00169   }
00170 
00171   // Release owning refs
00172   mPipeThread = nsnull;
00173   mObserver = nsnull;
00174   mObserverContext = nsnull;
00175 
00176   RemoveTempFile();
00177 
00178   // Clear console
00179   mByteBuf.Assign("");
00180 
00181   return NS_OK;
00182 }
00183 
00184 nsresult
00185 nsIPCBuffer::Init()
00186 {
00187   DEBUG_LOG(("nsIPCBuffer::Init: \n"));
00188 
00189   mInitialized = PR_TRUE;
00190 
00191   return NS_OK;
00192 }
00193 
00194 NS_IMETHODIMP
00195 nsIPCBuffer::Open(PRInt32 maxBytes, IPCBool overflowFile)
00196 {
00197   nsresult rv;
00198 
00199   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00200   NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED);
00201 
00202   DEBUG_LOG(("nsIPCBuffer::Open: %d, %d\n", maxBytes, (int) overflowFile));
00203   rv = Init();
00204   NS_ENSURE_SUCCESS(rv, rv);
00205 
00206   if (maxBytes <= 0) {
00207     mMaxBytes = PR_INT32_MAX;
00208   }
00209   else {
00210     mMaxBytes = maxBytes;
00211   }
00212   mOverflowFile = overflowFile;
00213 
00214   return NS_OK;
00215 }
00216 
00217 
00218 NS_IMETHODIMP
00219 nsIPCBuffer::OpenURI(nsIURI* aURI, PRInt32 maxBytes, IPCBool synchronous,
00220                      nsIRequestObserver* observer, nsISupports* context,
00221                      IPCBool overflowFile)
00222 {
00223   DEBUG_LOG(("nsIPCBuffer::OpenURI: \n"));
00224 
00225   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00226   NS_ENSURE_FALSE(mInitialized, NS_ERROR_ALREADY_INITIALIZED);
00227 
00228   // check input params. observer and context may be null
00229   NS_ENSURE_ARG(aURI);
00230 
00231   nsresult rv;
00232 
00233   rv = Init();
00234   NS_ENSURE_SUCCESS(rv, rv);
00235 
00236   if (maxBytes <= 0) {
00237     mMaxBytes = PR_INT32_MAX;
00238   }
00239   else {
00240     mMaxBytes = maxBytes;
00241   }
00242   mOverflowFile = overflowFile;
00243 
00244   mObserver = observer;
00245   mObserverContext = context;
00246 
00247   nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
00248   NS_ENSURE_SUCCESS(rv, rv);
00249 
00250   nsCOMPtr<nsIChannel> channel;
00251   rv = ioService->NewChannelFromURI(aURI, getter_AddRefs(channel));
00252   NS_ENSURE_SUCCESS(rv, rv);
00253 
00254   nsCOMPtr<nsISupports> ctxt = do_QueryInterface(aURI);
00255 
00256   if (!synchronous) {
00257     // Initiate asynchronous loading of URI
00258     rv = channel->AsyncOpen( (nsIStreamListener*) this, ctxt );
00259     NS_ENSURE_SUCCESS(rv, rv);
00260 
00261     DEBUG_LOG(("nsIPCBuffer::OpenURI: Starting asynchronous load ...\n"));
00262     return NS_OK;
00263   }
00264 
00265   // Synchronous loading (DOESN'T USUALLY WORK!!!)
00266   DEBUG_LOG(("nsIPCBuffer::OpenURI: Starting synchronous load ...\n"));
00267   nsCOMPtr<nsIInputStream> inputStream;
00268   rv = channel->Open(getter_AddRefs(inputStream));
00269   NS_ENSURE_SUCCESS(rv, rv);
00270 
00271   OnStartRequest(nsnull, mObserverContext);
00272 
00273   PRUint32 readCount;
00274   char buf[1024];
00275 
00276   while (1) {
00277     // Read and append output until end-of-file
00278     rv = inputStream->Read((char *) buf, 1024, &readCount);
00279     NS_ENSURE_SUCCESS(rv, rv);
00280 
00281     if (!readCount) break;
00282 
00283     rv = WriteBuf(buf, readCount);
00284     NS_ENSURE_SUCCESS(rv, rv);
00285   }
00286 
00287   // Close input stream
00288   inputStream->Close();
00289 
00290   OnStopRequest(nsnull, mObserverContext, 0);
00291 
00292   return NS_OK;
00293 }
00294 
00295 
00296 NS_IMETHODIMP
00297 nsIPCBuffer::GetStopped(IPCBool* _retval)
00298 {
00299   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00300   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00301 
00302   NS_ENSURE_ARG(_retval);
00303   *_retval = mRequestStopped;
00304   return NS_OK;
00305 }
00306 
00307 
00308 NS_IMETHODIMP
00309 nsIPCBuffer::GetTotalBytes(PRUint32* _retval)
00310 {
00311   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00312   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00313 
00314   NS_ENSURE_ARG(_retval);
00315   *_retval = mByteCount;
00316   return NS_OK;
00317 }
00318 
00319 
00320 NS_IMETHODIMP
00321 nsIPCBuffer::OpenInputStream(nsIInputStream** result)
00322 {
00323   DEBUG_LOG(("nsIPCBuffer::OpenInputStream: \n"));
00324 
00325   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00326   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00327 
00328   nsresult rv;
00329 
00330   if (!mRequestStopped) {
00331     ERROR_LOG(("nsIPCBuffer::OpenInputStream: ERROR - request not stopped\n"));
00332     return NS_ERROR_NOT_INITIALIZED;
00333   }
00334 
00335   mStreamOffset = 0;
00336 
00337   if (mByteCount && mTempFile) {
00338     rv = OpenTempInStream();
00339     NS_ENSURE_SUCCESS(rv, rv);
00340   }
00341 
00342   NS_ADDREF(*result = this);
00343   return NS_OK;
00344 }
00345 
00346 
00347 #define SAFE_TMP_FILENAME "nsenig.tmp"
00348 
00349 nsresult
00350 nsIPCBuffer::CreateTempFile()
00351 {
00352   nsresult rv;
00353 
00354   DEBUG_LOG(("nsIPCBuffer::CreateTempFile: \n"));
00355 
00356   if (mTempFile)
00357     return NS_ERROR_FILE_ALREADY_EXISTS;
00358 
00359   nsCOMPtr<nsIProperties> directoryService =
00360     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv);
00361   directoryService->Get(NS_OS_TEMP_DIR, NS_GET_IID(nsIFile),
00362     getter_AddRefs(mTempFile));
00363 
00364   NS_ABORT_IF_FALSE(mTempFile, "No temp folder?");
00365 
00366   if (! mTempFile)
00367     return NS_ERROR_UNEXPECTED;
00368 
00369   mTempFile->AppendNative(nsDependentCString(SAFE_TMP_FILENAME));
00370   rv = mTempFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 00600);
00371   NS_ENSURE_SUCCESS(rv, rv);
00372 
00373   nsCAutoString nativePath;
00374   mTempFile->GetNativePath(nativePath);
00375 
00376   DEBUG_LOG(("nsIPCBuffer::CreateTempFile: %s\n",
00377             nativePath.get()));
00378 
00379   mTempOutStream = do_CreateInstance(
00380     "@mozilla.org/network/file-output-stream;1",
00381     &rv);
00382   NS_ENSURE_SUCCESS(rv, rv);
00383 
00384   rv = mTempOutStream->Init(mTempFile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
00385     00600, 0);
00386   return rv;
00387 }
00388 
00389 
00390 nsresult
00391 nsIPCBuffer::WriteTempOutStream(const char* buf, PRUint32 count)
00392 {
00393   if (!mTempOutStream)
00394     return NS_ERROR_NOT_AVAILABLE;
00395 
00396   if (!count)
00397     return NS_OK;
00398 
00399   PRUint32 writeCount;
00400   nsresult rv = mTempOutStream->Write(buf, count, &writeCount);
00401 
00402   if (writeCount != count)
00403     return NS_ERROR_FAILURE;
00404 
00405   return rv;
00406 }
00407 
00408 nsresult
00409 nsIPCBuffer::CloseTempOutStream()
00410 {
00411   nsresult rv = NS_OK;
00412 
00413   DEBUG_LOG(("nsIPCBuffer::CloseTempOutStream: \n"));
00414 
00415   if (mTempOutStream) {
00416     nsresult flushRV = mTempOutStream->Flush();
00417     rv = mTempOutStream->Close();
00418 
00419     if (NS_SUCCEEDED(rv) && NS_FAILED(flushRV))
00420       rv = flushRV;
00421     mTempOutStream = nsnull;
00422   }
00423 
00424   return rv;
00425 }
00426 
00427 nsresult
00428 nsIPCBuffer::OpenTempInStream()
00429 {
00430   nsresult rv;
00431 
00432   DEBUG_LOG(("nsIPCBuffer::OpenTempInStream: \n"));
00433 
00434   if (!mTempFile)
00435     return NS_ERROR_NOT_AVAILABLE;
00436 
00437   if (mTempOutStream) {
00438     ERROR_LOG(("nsIPCBuffer::OpenTempInStream: ERROR - TempOutStream still open!\n"));
00439     return NS_ERROR_UNEXPECTED;
00440   }
00441 
00442   mTempInStream  = do_CreateInstance("@mozilla.org/network/file-input-stream;1",
00443     &rv);
00444   NS_ENSURE_SUCCESS(rv, rv);
00445 
00446   rv = mTempInStream->Init(mTempFile, PR_RDONLY, 00600, 0);
00447   return rv;
00448 }
00449 
00450 
00451 nsresult
00452 nsIPCBuffer::CloseTempInStream()
00453 {
00454   DEBUG_LOG(("nsIPCBuffer::CloseTempInStream: \n"));
00455   nsresult rv = NS_OK;
00456 
00457   if (mTempInStream) {
00458     rv = mTempInStream->Close();
00459     mTempInStream = nsnull;
00460   }
00461 
00462   return rv;
00463 }
00464 
00465 
00466 
00467 nsresult
00468 nsIPCBuffer::RemoveTempFile()
00469 {
00470   DEBUG_LOG(("nsIPCBuffer::RemoveTempFile: \n"));
00471 
00472   nsresult rv;
00473 
00474   if (mTempOutStream) {
00475     // Close overflow file
00476     CloseTempOutStream();
00477   }
00478 
00479   if (mTempInStream) {
00480     // Close overflow file
00481     CloseTempInStream();
00482   }
00483 
00484   if (mTempFile) {
00485     // delete temp file
00486     nsCAutoString nativePath;
00487     mTempFile->GetNativePath(nativePath);
00488     DEBUG_LOG(("nsIPCBuffer::RemoveTempFile: Removing %s\n",
00489                 nativePath.get()));
00490 
00491     rv = mTempFile->Remove(PR_FALSE);
00492     NS_ENSURE_SUCCESS(rv, rv);
00493 
00494     mTempFile = nsnull;
00495   }
00496 
00497   return NS_OK;
00498 }
00499 
00500 
00501 NS_IMETHODIMP
00502 nsIPCBuffer::GetData(char** _retval)
00503 {
00504   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00505   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00506 
00507   MutexAutoLock lock(mLock);
00508 
00509   if (!_retval)
00510     return NS_ERROR_NULL_POINTER;
00511 
00512   // Copy portion of console data to be returned
00513   nsCAutoString bufCopy (mByteBuf);
00514 
00515   // Replace any NULs with '0'
00516   PRInt32 nulIndex = 0;
00517   while (nulIndex != -1) {
00518     nulIndex = bufCopy.FindChar(char(0));
00519     if (nulIndex != -1) {
00520       bufCopy.Replace(nulIndex, 1, "0", 1);
00521     }
00522   }
00523 
00524   // Duplicate new C string
00525   *_retval = ToNewCString(bufCopy);
00526   if (!*_retval)
00527     return NS_ERROR_OUT_OF_MEMORY;
00528 
00529   return NS_OK;
00530 }
00531 
00532 
00534 // nsIPipeListener methods (thread-safe)
00536 
00537 NS_IMETHODIMP
00538 nsIPCBuffer::Observe(nsIRequestObserver* observer, nsISupports* context)
00539 {
00540   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00541   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00542 
00543   NS_ENSURE_ARG(observer);
00544 
00545   MutexAutoLock lock(mLock);
00546   DEBUG_LOG(("nsIPCBuffer::Observe: %p, %p\n", observer, context));
00547 
00548   mObserver = observer;
00549   mObserverContext = context;
00550 
00551   return NS_OK;
00552 }
00553 
00554 
00555 NS_IMETHODIMP
00556 nsIPCBuffer::GetJoinable(IPCBool *_retval)
00557 {
00558   DEBUG_LOG(("nsIPCBuffer::GetJoinable: 1\n"));
00559 
00560   *_retval = PR_TRUE;
00561 
00562   return NS_OK;
00563 }
00564 
00565 
00566 NS_IMETHODIMP
00567 nsIPCBuffer::Shutdown()
00568 {
00569   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00570   // allow to perform even if mFinalized is true
00571 
00572   MutexAutoLock lock(mLock);
00573   DEBUG_LOG(("nsIPCBuffer::Shutdown:\n"));
00574 
00575   Finalize(PR_FALSE);
00576 
00577   return NS_OK;
00578 }
00579 
00580 
00581 
00582 NS_IMETHODIMP
00583 nsIPCBuffer::GetByteData(PRUint32 *count, char **data)
00584 {
00585   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00586   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00587 
00588   MutexAutoLock lock(mLock);
00589 
00590   DEBUG_LOG(("nsIPCBuffer::GetByteData:\n"));
00591 
00592   if (!count || !data)
00593     return NS_ERROR_NULL_POINTER;
00594 
00595   // Copy bytes
00596   *count = mByteBuf.Length();
00597   *data = reinterpret_cast<char*>(nsMemory::Alloc((*count)+1));
00598   if (!*data)
00599     return NS_ERROR_OUT_OF_MEMORY;
00600 
00601   memcpy(*data, mByteBuf.get(), *count);
00602 
00603   // NUL terminate byte array (just to be safe!)
00604   (*data)[*count] = '\0';
00605 
00606   return NS_OK;
00607 }
00608 
00609 
00610 NS_IMETHODIMP
00611 nsIPCBuffer::GetOverflowed(IPCBool *_retval)
00612 {
00613   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00614   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00615 
00616   MutexAutoLock lock(mLock);
00617 
00618   DEBUG_LOG(("nsIPCBuffer::GetOverflowed: %d\n", (int) mOverflowed));
00619 
00620   *_retval = mOverflowed;
00621 
00622   return NS_OK;
00623 }
00624 
00625 
00626 NS_IMETHODIMP
00627 nsIPCBuffer::Write(const char* str)
00628 {
00629   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00630   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00631 
00632   NS_ENSURE_ARG(str);
00633 
00634   // Note: Locking occurs in WriteBuf
00635 
00636   DEBUG_LOG(("nsIPCBuffer::Write: %s\n", str));
00637 
00638   PRUint32 len = strlen(str);
00639   if (!len)
00640     return NS_OK;
00641 
00642   return WriteBuf(str, len);
00643 }
00644 
00645 
00646 NS_IMETHODIMP
00647 nsIPCBuffer::WriteBuf(const char* buf, PRUint32 count)
00648 {
00649   DEBUG_LOG(("nsIPCBuffer::WriteBuf: %d (%d)\n", count, mByteCount));
00650 
00651   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00652   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00653 
00654   NS_ENSURE_ARG(buf);
00655 
00656   nsresult rv;
00657   MutexAutoLock lock(mLock);
00658 
00659   if (count <= 0)
00660     return NS_OK;
00661 
00662   mByteCount += count;
00663 
00664   if (mOverflowed) {
00665     if (!mOverflowFile)
00666       return NS_OK;
00667 
00668     rv = WriteTempOutStream(buf, count);
00669 
00670     return rv;
00671   }
00672 
00673   // Find space available in buffer
00674   PRInt32 nAvail = mMaxBytes - mByteBuf.Length();
00675 
00676   if (nAvail >= (PRInt32) count) {
00677     mByteBuf.Append(buf, count);
00678     return NS_OK;
00679   }
00680 
00681   if (nAvail > 0) {
00682     mByteBuf.Append(buf, nAvail);
00683   }
00684 
00685   mOverflowed = PR_TRUE;
00686   DEBUG_LOG(("nsIPCBuffer::WriteBuf: buffer overflow\n"));
00687 
00688   if (!mOverflowFile)
00689     return NS_OK;
00690 
00691   CreateTempFile();
00692 
00693   // Write out previously buffered data first
00694   rv = WriteTempOutStream(mByteBuf.get(), mByteBuf.Length());
00695   NS_ENSURE_SUCCESS(rv, rv);
00696 
00697   rv = WriteTempOutStream(buf+nAvail, count-nAvail);
00698   return rv;
00699 }
00700 
00701 NS_IMETHODIMP
00702 nsIPCBuffer::Join()
00703 {
00704   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00705   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00706 
00707   nsresult rv;
00708 
00709   {
00710     // Nested lock to avoid deadlock while waiting for Join
00711     MutexAutoLock lock(mLock);
00712     DEBUG_LOG(("nsIPCBuffer::Join:\n"));
00713 
00714     if (mThreadJoined || !mPipeThread)
00715       return NS_OK;
00716 
00717     if (mPipeWrite) {
00718       // Close write pipe before joining
00719       IPC_Close(mPipeWrite);
00720       mPipeWrite = IPC_NULL_HANDLE;
00721     }
00722   }
00723 
00724   rv = mPipeThread->Shutdown();
00725 
00726   NS_ENSURE_SUCCESS(rv, rv);
00727 
00728   mThreadJoined = PR_TRUE;
00729   return NS_OK;
00730 }
00731 
00732 
00733 NS_IMETHODIMP
00734 nsIPCBuffer::GetFileDesc(IPCFileDesc **_retval)
00735 {
00736   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00737   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00738 
00739   nsresult rv;
00740 
00741   MutexAutoLock lock(mLock);
00742 
00743   DEBUG_LOG(("nsIPCBuffer::GetFileDesc:\n"));
00744 
00745   NS_ENSURE_ARG_POINTER(_retval);
00746 
00747   if (!mFinalized && !mPipeThread) {
00748     // Create pipe pair
00749     PRStatus status = IPC_CreateInheritablePipe(&mPipeRead, &mPipeWrite,
00750                                               PR_FALSE, PR_TRUE);
00751     if (status != PR_SUCCESS) {
00752       ERROR_LOG(("nsIPCBuffer::GetFileDesc: IPC_CreateInheritablePipe failed\n"));
00753       return NS_ERROR_FAILURE;
00754     }
00755 
00756     // Spin up a new thread to handle STDOUT polling
00757     rv = NS_NewThread(getter_AddRefs(mPipeThread), this);
00758 
00759     NS_ENSURE_SUCCESS(rv, rv);
00760   }
00761 
00762   if (mPipeWrite == IPC_NULL_HANDLE)
00763     return NS_ERROR_FAILURE;
00764 
00765   *_retval = mPipeWrite;
00766   return NS_OK;
00767 }
00768 
00770 // nsIRequestObserver methods
00772 
00773 NS_IMETHODIMP
00774 nsIPCBuffer::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
00775 {
00776   DEBUG_LOG(("nsIPCBuffer::OnStartRequest:\n"));
00777 
00778   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00779   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00780 
00781   nsIRequestObserver* observer;
00782   nsISupports* observerContext;
00783   {
00784     MutexAutoLock lock(mLock);
00785 
00786     mRequestStarted = PR_TRUE;
00787 
00788     if (!mObserver)
00789       return NS_OK;
00790 
00791     observer = mObserver;
00792     observerContext = mObserverContext;
00793   }
00794 
00795   return observer->OnStartRequest(aRequest, observerContext);
00796 }
00797 
00798 NS_IMETHODIMP
00799 nsIPCBuffer::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
00800                              nsresult aStatus)
00801 {
00802   DEBUG_LOG(("nsIPCBuffer::OnStopRequest:\n"));
00803 
00804   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00805   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00806 
00807   nsIRequestObserver* observer;
00808   nsISupports* observerContext;
00809   {
00810     MutexAutoLock lock(mLock);
00811 
00812     mRequestStopped = PR_TRUE;
00813     CloseTempOutStream();
00814 
00815     if (!mObserver)
00816       return NS_OK;
00817 
00818     observer = mObserver;
00819     observerContext = mObserverContext;
00820   }
00821 
00822   return observer->OnStopRequest(aRequest, observerContext, aStatus);
00823 }
00824 
00826 // nsIStreamListener method
00828 
00829 NS_IMETHODIMP
00830 nsIPCBuffer::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
00831                               nsIInputStream *aInputStream,
00832                               PRUint32 aSourceOffset,
00833                               PRUint32 aLength)
00834 {
00835   nsresult rv = NS_OK;
00836 
00837   DEBUG_LOG(("nsIPCBuffer::OnDataAVailable: %d\n", aLength));
00838 
00839   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00840   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00841 
00842   NS_ENSURE_ARG(aInputStream);
00843   NS_ENSURE_ARG_MIN(aLength, 0);
00844 
00845   char buf[kCharMax];
00846   PRUint32 readCount, readMax;
00847 
00848   while (aLength > 0) {
00849     readMax = (aLength < kCharMax) ? aLength : kCharMax;
00850     rv = aInputStream->Read((char *) buf, readMax, &readCount);
00851     if (NS_FAILED(rv)) {
00852       ERROR_LOG(("nsIPCBuffer::OnDataAvailable: Error in reading from input stream, %x\n",
00853         rv));
00854       return rv;
00855     }
00856 
00857     if (readCount <= 0) return NS_OK;
00858 
00859     rv = WriteBuf(buf, readCount);
00860     if (NS_FAILED(rv)) return rv;
00861 
00862     aLength -= readCount;
00863   }
00864 
00865   return NS_OK;
00866 }
00867 
00869 // nsIRunnable methods:
00870 // (runs as a new thread)
00872 
00873 NS_IMETHODIMP
00874 nsIPCBuffer::Run()
00875 {
00876 #ifdef FORCE_PR_LOG
00877   nsCOMPtr<nsIThread> myThread;
00878   IPC_GET_THREAD(myThread);
00879   DEBUG_LOG(("nsIPCBuffer::Run: myThread=%p\n", myThread.get()));
00880 #endif
00881 
00882   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00883   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00884 
00885   // Blocked read loop
00886   while (1) {
00887     char buf[kCharMax];
00888     PRInt32 readCount;
00889 
00890     // Read data from pipe (blocking)
00891     readCount = IPC_Read(mPipeRead, (char *) buf, kCharMax);
00892 
00893     DEBUG_LOG(("nsIPCBuffer::Run: Read %d chars\n", readCount));
00894 
00895     if (readCount <= 0)
00896       break;
00897 
00898 #if 0
00899     // Debugging code
00900     if (readCount < (int) kCharMax) {
00901       buf[readCount] = '\0';
00902       DEBUG_LOG(("nsIPCBuffer::Run: buf='%s'\n", buf));
00903     }
00904 #endif
00905 
00906     // Append data read to console
00907     WriteBuf(buf, readCount);
00908   }
00909 
00910   // Clear any NSPR interrupt
00911   PR_ClearInterrupt();
00912 
00913   // Close read pipe
00914   IPC_Close(mPipeRead);
00915   mPipeRead = IPC_NULL_HANDLE;
00916 
00917   return NS_OK;
00918 }
00919 
00921 // nsIInputStream methods
00923 
00924 NS_IMETHODIMP
00925 nsIPCBuffer::Available(PRUint32* _retval)
00926 {
00927   NS_ENSURE_ARG(_retval);
00928 
00929   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00930   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00931 
00932   *_retval = (mByteCount > mStreamOffset) ?
00933               mByteCount - mStreamOffset : 0;
00934 
00935   DEBUG_LOG(("nsIPCBuffer::Available: %d (%d)\n", *_retval, mByteCount));
00936 
00937   return NS_OK;
00938 }
00939 
00940 NS_IMETHODIMP
00941 nsIPCBuffer::Read(char* buf, PRUint32 count,
00942                          PRUint32 *readCount)
00943 {
00944   DEBUG_LOG(("nsIPCBuffer::Read: %d\n", count));
00945 
00946   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00947   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00948 
00949   nsresult rv;
00950 
00951   if (!buf || !readCount)
00952     return NS_ERROR_NULL_POINTER;
00953 
00954   PRInt32 avail = (mByteCount > mStreamOffset) ?
00955                    mByteCount - mStreamOffset : 0;
00956 
00957   PRUint32 readyCount = ((PRUint32) avail > count) ? count : avail;
00958 
00959   if (readyCount) {
00960     if (mTempInStream) {
00961       rv = mTempInStream->Read((char *)buf, readyCount, readCount);
00962       NS_ENSURE_SUCCESS(rv, rv);
00963     } else {
00964       memcpy(buf, mByteBuf.get()+mStreamOffset, readyCount);
00965       *readCount = readyCount;
00966     }
00967   }
00968 
00969   mStreamOffset += *readCount;
00970 
00971   if (mStreamOffset >= mByteCount) {
00972     Close();
00973   }
00974 
00975   return NS_OK;
00976 }
00977 
00978 NS_IMETHODIMP
00979 nsIPCBuffer::ReadSegments(nsWriteSegmentFun writer,
00980                           void * aClosure, PRUint32 count,
00981                           PRUint32 *readCount)
00982 {
00983   DEBUG_LOG(("nsIPCBuffer::ReadSegments: %d\n", count));
00984 
00985   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
00986   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
00987 
00988   nsresult rv;
00989 
00990   if (!readCount)
00991     return NS_ERROR_NULL_POINTER;
00992 
00993   PRUint32 avail, readyCount, writeCount;
00994 
00995   *readCount = 0;
00996   if (!mTempInStream) {
00997 
00998     while ((count > 0) && (mStreamOffset < mByteCount)) {
00999       avail = mByteCount - mStreamOffset;
01000       readyCount = ((PRUint32) avail > count) ? count : avail;
01001 
01002       rv = writer((nsIInputStream*)(this),
01003                   aClosure, mByteBuf.get()+mStreamOffset,
01004                   mStreamOffset, readyCount, &writeCount);
01005       NS_ENSURE_SUCCESS(rv, rv);
01006 
01007       if (!writeCount)
01008         return (NS_ERROR_FAILURE);
01009 
01010       DEBUG_LOG(("nsIPCBuffer::ReadSegments: writer %d\n", writeCount));
01011 
01012       *readCount    += writeCount;
01013       mStreamOffset += writeCount;
01014       count         -= writeCount;
01015     }
01016 
01017   } else {
01018     char buf[kCharMax];
01019 
01020     while ((count > 0) && (mStreamOffset < mByteCount)) {
01021       avail = (count < kCharMax) ? count : kCharMax;
01022       rv = mTempInStream->Read((char *) buf, avail, &readyCount);
01023       NS_ENSURE_SUCCESS(rv, rv);
01024 
01025       if (!readyCount) {
01026         ERROR_LOG(("nsIPCBuffer::ReadSegments: Error in reading from TempInputStream\n"));
01027         return NS_ERROR_FAILURE;
01028       }
01029 
01030       rv = writer((nsIInputStream*)(this),
01031                   aClosure, buf,
01032                   mStreamOffset, readyCount, &writeCount);
01033       NS_ENSURE_SUCCESS(rv, rv);
01034       if (!writeCount)
01035         return NS_ERROR_FAILURE;
01036 
01037       DEBUG_LOG(("nsIPCBuffer::ReadSegments: writer %d (Temp)\n", writeCount));
01038 
01039       *readCount    += writeCount;
01040       mStreamOffset += writeCount;
01041       count         -= writeCount;
01042     }
01043   }
01044 
01045   if (mStreamOffset >= mByteCount) {
01046     // End-of-file
01047     Close();
01048   }
01049 
01050   return NS_OK;
01051 }
01052 
01053 NS_IMETHODIMP
01054 nsIPCBuffer::IsNonBlocking(IPCBool *aNonBlocking)
01055 {
01056   DEBUG_LOG(("nsIPCBuffer::IsNonBlocking: \n"));
01057 
01058   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
01059   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
01060 
01061   *aNonBlocking = (!mTempInStream);
01062   return NS_OK;
01063 }
01064 
01065 NS_IMETHODIMP
01066 nsIPCBuffer::Close()
01067 {
01068   DEBUG_LOG(("nsIPCBuffer::Close: \n"));
01069 
01070   NS_ENSURE_FALSE(mFinalized, NS_ERROR_NOT_AVAILABLE);
01071   NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
01072 
01073   mStreamOffset = 0;
01074   mByteCount = 0;
01075   mByteBuf.Assign("");
01076 
01077   RemoveTempFile();
01078   return NS_OK;
01079 }
01080 
01081 
01082 #ifdef XP_WIN_IPC
01083 PRStatus IPC_CreateInheritablePipe(IPCFileDesc* *readPipe,
01084                                         IPCFileDesc* *writePipe,
01085                                         IPCBool readInherit,
01086                                         IPCBool writeInherit)
01087 {
01088   BOOL bRetVal;
01089 
01090   // Security attributes for inheritable handles
01091   SECURITY_ATTRIBUTES securityAttr;
01092   securityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
01093   securityAttr.lpSecurityDescriptor = NULL;
01094   securityAttr.bInheritHandle = TRUE;
01095 
01096   // Create pipe
01097   HANDLE hReadPipe, hWritePipe;
01098   bRetVal = CreatePipe( &hReadPipe, &hWritePipe,
01099                         &securityAttr, 0);
01100   if (!bRetVal)
01101     return PR_FAILURE;
01102 
01103   HANDLE hPipeTem;
01104 
01105   if (!readInherit) {
01106     // Make read handle uninheritable
01107     bRetVal = DuplicateHandle( GetCurrentProcess(),
01108                                hReadPipe,
01109                                GetCurrentProcess(),
01110                                &hPipeTem,
01111                                0,
01112                                FALSE,
01113                                DUPLICATE_SAME_ACCESS);
01114     CloseHandle(hReadPipe);
01115 
01116     if (!bRetVal) {
01117       CloseHandle(hWritePipe);
01118       return PR_FAILURE;
01119     }
01120     hReadPipe = hPipeTem;
01121   }
01122 
01123   if (!writeInherit) {
01124     // Make write handle uninheritable
01125     bRetVal = DuplicateHandle( GetCurrentProcess(),
01126                                hWritePipe,
01127                                GetCurrentProcess(),
01128                                &hPipeTem,
01129                                0,
01130                                FALSE,
01131                                DUPLICATE_SAME_ACCESS);
01132     CloseHandle(hWritePipe);
01133 
01134     if (!bRetVal) {
01135       CloseHandle(hReadPipe);
01136       return PR_FAILURE;
01137     }
01138     hWritePipe = hPipeTem;
01139   }
01140 
01141   *readPipe  = (void*) hReadPipe;
01142   *writePipe = (void*) hWritePipe;
01143 
01144   return PR_SUCCESS;
01145 }
01146 
01147 
01148 PRInt32 IPC_ReadWin32(IPCFileDesc* fd, void *buf, PRInt32 amount)
01149 {
01150   unsigned long bytes;
01151 
01152   if (ReadFile((HANDLE) fd,
01153                (LPVOID) buf,
01154                amount,
01155                &bytes,
01156                NULL)) {
01157     return bytes;
01158   }
01159 
01160   DWORD dwLastError = GetLastError();
01161 
01162   if (dwLastError == ERROR_BROKEN_PIPE)
01163     return 0;
01164 
01165   return -1;
01166 }
01167 
01168 PRStatus IPC_CloseWin32(IPCFileDesc* fd)
01169 {
01170   return (CloseHandle((HANDLE) fd)) ? PR_SUCCESS : PR_FAILURE;
01171 }
01172 
01173 #else
01174 PRStatus IPC_CreateInheritablePipe(PRFileDesc* *readPipe,
01175                                        PRFileDesc* *writePipe,
01176                                        IPCBool readInherit,
01177                                        IPCBool writeInherit)
01178 {
01179   PRStatus status;
01180 
01181   //status = PR_NewTCPSocketPair(fd);
01182   status = PR_CreatePipe(readPipe, writePipe);
01183   if (status != PR_SUCCESS)
01184     return status;
01185 
01186   // Hack to handle Win32 problem: PR_SetFDInheritable returns error
01187   // when we try to return off inheritability. However, inheritability is
01188   // supposed to be off by default, so it shouldn't really matter.
01189   status = PR_SUCCESS;
01190 #ifdef XP_WIN
01191   if (readInherit)
01192 #endif
01193     status = PR_SetFDInheritable(*readPipe, readInherit);
01194   if (status != PR_SUCCESS)
01195     return status;
01196 
01197 #ifdef XP_WIN
01198   if (writeInherit)
01199 #endif
01200     status = PR_SetFDInheritable(*writePipe, writeInherit);
01201   if (status != PR_SUCCESS)
01202     return status;
01203 
01204   return PR_SUCCESS;
01205 }
01206 #endif