JSBool TCP_connect (JSContext* cx, JSObject* object, uintN argc, jsval* argv, jsval* rval) { char* host; int port = -1; jsdouble timeout = 30; JS_BeginRequest(cx); if (argc < 1) { JS_ReportError(cx, "Not enough parameters."); JS_EndRequest(cx); return JS_FALSE; } jsval jsConnected; JS_GetProperty(cx, object, "connected", &jsConnected); if (jsConnected == JSVAL_TRUE) { JS_ReportError(cx, "The socket is already connected."); JS_EndRequest(cx); return JS_FALSE; } switch (argc) { case 3: JS_ValueToNumber(cx, argv[2], &timeout); case 2: JS_ValueToInt32(cx, argv[1], &port); case 1: host = JS_GetStringBytes(JS_ValueToString(cx, argv[0])); } TCPInformation* data = (TCPInformation*) JS_GetPrivate(cx, object); PRNetAddr addr; if (__Sockets_initAddr(&addr, host, port) == PR_FAILURE) { *rval = JSVAL_FALSE; JS_EndRequest(cx); return JS_TRUE; } if (PR_Connect(data->socket, &addr, (timeout == -1) ? PR_INTERVAL_NO_TIMEOUT : PR_MicrosecondsToInterval(timeout*1000000)) == PR_FAILURE) { if (PR_GetError() == PR_CONNECT_RESET_ERROR) { JS_ReportError(cx, "Connection reset by peer."); } jsConnected = JSVAL_FALSE; JS_SetProperty(cx, object, "connected", &jsConnected); JS_EndRequest(cx); return JS_FALSE; } jsConnected = JSVAL_TRUE; JS_SetProperty(cx, object, "connected", &jsConnected); JS_EndRequest(cx); return JS_TRUE; }
JSBool TCP_accept (JSContext* cx, JSObject* object, uintN argc, jsval* argv, jsval* rval) { jsdouble timeout = -1; if (argc) { JS_ValueToNumber(cx, argv[0], &timeout); } TCPInformation* data = (TCPInformation*) JS_GetPrivate(cx, object); JS_BeginRequest(cx); JS_EnterLocalRootScope(cx); JSObject* sock = JS_NewObject(cx, &TCP_class, JS_GetPrototype(cx, object), NULL); TCPInformation* newData = new TCPInformation; JS_SetPrivate(cx, sock, newData); PRNetAddr addr; newData->socket = PR_Accept(data->socket, &addr, (timeout == -1) ? PR_INTERVAL_NO_TIMEOUT : PR_MicrosecondsToInterval(timeout*1000000)); jsval property = JSVAL_TRUE; JS_SetProperty(cx, sock, "connected", &property); *rval = OBJECT_TO_JSVAL(sock); JS_LeaveLocalRootScope(cx); JS_EndRequest(cx); return JS_TRUE; }
static void TestConversions(void) { PRIntervalTime ticks = PR_TicksPerSecond(); if (debug_mode) { PR_fprintf(output, "PR_TicksPerSecond: %ld\n\n", ticks); PR_fprintf(output, "PR_SecondsToInterval(1): %ld\n", PR_SecondsToInterval(1)); PR_fprintf(output, "PR_MillisecondsToInterval(1000): %ld\n", PR_MillisecondsToInterval(1000)); PR_fprintf(output, "PR_MicrosecondsToInterval(1000000): %ld\n\n", PR_MicrosecondsToInterval(1000000)); PR_fprintf(output, "PR_SecondsToInterval(3): %ld\n", PR_SecondsToInterval(3)); PR_fprintf(output, "PR_MillisecondsToInterval(3000): %ld\n", PR_MillisecondsToInterval(3000)); PR_fprintf(output, "PR_MicrosecondsToInterval(3000000): %ld\n\n", PR_MicrosecondsToInterval(3000000)); PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); ticks *= 3; PR_fprintf(output, "PR_IntervalToSeconds(%ld): %ld\n", ticks, PR_IntervalToSeconds(ticks)); PR_fprintf(output, "PR_IntervalToMilliseconds(%ld): %ld\n", ticks, PR_IntervalToMilliseconds(ticks)); PR_fprintf(output, "PR_IntervalToMicroseconds(%ld): %ld\n\n", ticks, PR_IntervalToMicroseconds(ticks)); } /*end debug mode */ } /* TestConversions */
PRStatus TimelineInit(void) { char *timeStr; char *fileName; PRInt32 secs, msecs; PRFileDesc *fd; PRInt64 tmp1, tmp2; PRStatus status = PR_NewThreadPrivateIndex( &gTLSIndex, ThreadDestruct ); NS_WARN_IF_FALSE(status==0, "TimelineService could not allocate TLS storage."); timeStr = PR_GetEnv("NS_TIMELINE_INIT_TIME"); #ifdef XP_MAC initInterval = PR_IntervalNow(); #endif // NS_TIMELINE_INIT_TIME only makes sense for the main thread, so if it // exists, set it there. If not, let normal thread management code take // care of setting the init time. if (timeStr != NULL && 2 == PR_sscanf(timeStr, "%d.%d", &secs, &msecs)) { PRTime &initTime = GetThisThreadData()->initTime; LL_MUL(tmp1, (PRInt64)secs, 1000000); LL_MUL(tmp2, (PRInt64)msecs, 1000); LL_ADD(initTime, tmp1, tmp2); #ifdef XP_MAC initInterval -= PR_MicrosecondsToInterval( (PRUint32)(PR_Now() - initTime)); #endif } // Get the log file. #ifdef XP_MAC fileName = "timeline.txt"; #else fileName = PR_GetEnv("NS_TIMELINE_LOG_FILE"); #endif if (fileName != NULL && (fd = PR_Open(fileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0666)) != NULL) { timelineFD = fd; PR_fprintf(fd, "NOTE: due to asynchrony, the indentation that you see does" " not necessarily correspond to nesting in the code.\n\n"); } // Runtime disable of timeline if (PR_GetEnv("NS_TIMELINE_ENABLE")) gTimelineDisabled = PR_FALSE; return PR_SUCCESS; }
// this is used for Send without UI nsresult nsMapiHook::BlindSendMail (unsigned long aSession, nsIMsgCompFields * aCompFields) { nsresult rv = NS_OK ; if (!IsBlindSendAllowed()) return NS_ERROR_FAILURE; /** create nsIMsgComposeParams obj and other fields to populate it **/ nsCOMPtr<nsIDOMWindowInternal> hiddenWindow; // get parent window nsCOMPtr<nsIAppShellService> appService = do_GetService( "@mozilla.org/appshell/appShellService;1", &rv); if (NS_FAILED(rv)|| (!appService) ) return rv ; rv = appService->GetHiddenDOMWindow(getter_AddRefs(hiddenWindow)); if ( NS_FAILED(rv) ) return rv ; // smtp password and Logged in used IdKey from MapiConfig (session obj) nsMAPIConfiguration * pMapiConfig = nsMAPIConfiguration::GetMAPIConfiguration() ; if (!pMapiConfig) return NS_ERROR_FAILURE ; // get the singelton obj PRUnichar * password = pMapiConfig->GetPassword(aSession) ; // password nsCAutoString smtpPassword; LossyCopyUTF16toASCII(password, smtpPassword); // Id key nsCString MsgIdKey; pMapiConfig->GetIdKey(aSession, MsgIdKey); // get the MsgIdentity for the above key using AccountManager nsCOMPtr <nsIMsgAccountManager> accountManager = do_GetService (NS_MSGACCOUNTMANAGER_CONTRACTID) ; if (NS_FAILED(rv) || (!accountManager) ) return rv ; nsCOMPtr <nsIMsgIdentity> pMsgId ; rv = accountManager->GetIdentity (MsgIdKey, getter_AddRefs(pMsgId)) ; if (NS_FAILED(rv) ) return rv ; // create a send listener to get back the send status nsCOMPtr <nsIMsgSendListener> sendListener ; rv = nsMAPISendListener::CreateMAPISendListener(getter_AddRefs(sendListener)) ; if (NS_FAILED(rv) || (!sendListener) ) return rv; // create the compose params object nsCOMPtr<nsIMsgComposeParams> pMsgComposeParams (do_CreateInstance(NS_MSGCOMPOSEPARAMS_CONTRACTID, &rv)); if (NS_FAILED(rv) || (!pMsgComposeParams) ) return rv ; // populate the compose params PRBool forcePlainText; aCompFields->GetForcePlainText(&forcePlainText); pMsgComposeParams->SetType(nsIMsgCompType::New); pMsgComposeParams->SetFormat(forcePlainText ? nsIMsgCompFormat::PlainText : nsIMsgCompFormat::HTML); pMsgComposeParams->SetIdentity(pMsgId); pMsgComposeParams->SetComposeFields(aCompFields); pMsgComposeParams->SetSendListener(sendListener) ; pMsgComposeParams->SetSmtpPassword(smtpPassword.get()); // create the nsIMsgCompose object to send the object nsCOMPtr<nsIMsgCompose> pMsgCompose (do_CreateInstance(NS_MSGCOMPOSE_CONTRACTID, &rv)); if (NS_FAILED(rv) || (!pMsgCompose) ) return rv ; /** initialize nsIMsgCompose, Send the message, wait for send completion response **/ rv = pMsgCompose->Initialize(hiddenWindow, pMsgComposeParams) ; if (NS_FAILED(rv)) return rv ; return pMsgCompose->SendMsg(nsIMsgSend::nsMsgDeliverNow, pMsgId, nsnull, nsnull, nsnull) ; if (NS_FAILED(rv)) return rv ; // assign to interface pointer from nsCOMPtr to facilitate typecast below nsIMsgSendListener * pSendListener = sendListener ; // we need to wait here to make sure that we return only after send is completed // so we will have a event loop here which will process the events till the Send IsDone. nsIThread *thread = NS_GetCurrentThread(); while ( !((nsMAPISendListener *) pSendListener)->IsDone() ) { PR_CEnterMonitor(pSendListener); PR_CWait(pSendListener, PR_MicrosecondsToInterval(1000UL)); PR_CExitMonitor(pSendListener); NS_ProcessPendingEvents(thread); } return rv ; }
nsresult nsMsgCopy::DoCopy(nsIFile *aDiskFile, nsIMsgFolder *dstFolder, nsIMsgDBHdr *aMsgToReplace, bool aIsDraft, nsIMsgWindow *msgWindow, nsIMsgSend *aMsgSendObj) { nsresult rv = NS_OK; // Check sanity if ((!aDiskFile) || (!dstFolder)) return NS_ERROR_INVALID_ARG; //Call copyservice with dstFolder, disk file, and txnManager if(NS_SUCCEEDED(rv)) { nsRefPtr<CopyListener> copyListener = new CopyListener(); if (!copyListener) return NS_ERROR_OUT_OF_MEMORY; copyListener->SetMsgComposeAndSendObject(aMsgSendObj); nsCOMPtr<nsIThread> thread; if (aIsDraft) { nsCOMPtr<nsIMsgImapMailFolder> imapFolder = do_QueryInterface(dstFolder); nsCOMPtr<nsIMsgAccountManager> accountManager = do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; bool shutdownInProgress = false; rv = accountManager->GetShutdownInProgress(&shutdownInProgress); if (NS_SUCCEEDED(rv) && shutdownInProgress && imapFolder) { // set the following only when we were in the middle of shutdown // process copyListener->mCopyInProgress = true; thread = do_GetCurrentThread(); } } nsCOMPtr<nsIMsgCopyService> copyService = do_GetService(NS_MSGCOPYSERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = copyService->CopyFileMessage(aDiskFile, dstFolder, aMsgToReplace, aIsDraft, aIsDraft ? 0 : nsMsgMessageFlags::Read, EmptyCString(), copyListener, msgWindow); // copyListener->mCopyInProgress can only be set when we are in the // middle of the shutdown process while (copyListener->mCopyInProgress) { PR_CEnterMonitor(copyListener); PR_CWait(copyListener, PR_MicrosecondsToInterval(1000UL)); PR_CExitMonitor(copyListener); if (thread) NS_ProcessPendingEvents(thread); } } return rv; }
static PRInt32 socket_io_wait( PROsfd osfd, PRInt32 fd_type, PRIntervalTime timeout) { PRInt32 rv = -1; struct timeval tv; PRThread *me = _PR_MD_CURRENT_THREAD(); PRIntervalTime elapsed, remaining; PRBool wait_for_remaining; fd_set rd_wr, ex; int err, len; switch (timeout) { case PR_INTERVAL_NO_WAIT: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); break; case PR_INTERVAL_NO_TIMEOUT: /* * This is a special case of the 'default' case below. * Please see the comments there. */ tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; FD_ZERO(&rd_wr); FD_ZERO(&ex); do { FD_SET(osfd, &rd_wr); FD_SET(osfd, &ex); switch( fd_type ) { case READ_FD: rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv); break; case WRITE_FD: rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); break; case CONNECT_FD: rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv); break; default: PR_ASSERT(0); break; } /* end switch() */ if (rv == -1 ) { _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); break; } if ( rv > 0 && fd_type == CONNECT_FD ) { /* * Call Sleep(0) to work around a Winsock timing bug. */ Sleep(0); if (FD_ISSET((SOCKET)osfd, &ex)) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return -1; } if (err != 0) _PR_MD_MAP_CONNECT_ERROR(err); else PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } if (FD_ISSET((SOCKET)osfd, &rd_wr)) { /* it's connected */ return 1; } PR_ASSERT(0); } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } } while (rv == 0); break; default: remaining = timeout; FD_ZERO(&rd_wr); FD_ZERO(&ex); do { /* * We block in _MD_SELECT for at most * _PR_INTERRUPT_CHECK_INTERVAL_SECS seconds, * so that there is an upper limit on the delay * before the interrupt bit is checked. */ wait_for_remaining = PR_TRUE; tv.tv_sec = PR_IntervalToSeconds(remaining); if (tv.tv_sec > _PR_INTERRUPT_CHECK_INTERVAL_SECS) { wait_for_remaining = PR_FALSE; tv.tv_sec = _PR_INTERRUPT_CHECK_INTERVAL_SECS; tv.tv_usec = 0; } else { tv.tv_usec = PR_IntervalToMicroseconds( remaining - PR_SecondsToInterval(tv.tv_sec)); } FD_SET(osfd, &rd_wr); FD_SET(osfd, &ex); switch( fd_type ) { case READ_FD: rv = _MD_SELECT(0, &rd_wr, NULL, NULL, &tv); break; case WRITE_FD: rv = _MD_SELECT(0, NULL, &rd_wr, NULL, &tv); break; case CONNECT_FD: rv = _MD_SELECT(0, NULL, &rd_wr, &ex, &tv); break; default: PR_ASSERT(0); break; } /* end switch() */ if (rv == -1) { _PR_MD_MAP_SELECT_ERROR(WSAGetLastError()); break; } if ( rv > 0 && fd_type == CONNECT_FD ) { /* * Call Sleep(0) to work around a Winsock timing bug. */ Sleep(0); if (FD_ISSET((SOCKET)osfd, &ex)) { len = sizeof(err); if (getsockopt(osfd, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == SOCKET_ERROR) { _PR_MD_MAP_GETSOCKOPT_ERROR(WSAGetLastError()); return -1; } if (err != 0) _PR_MD_MAP_CONNECT_ERROR(err); else PR_SetError(PR_UNKNOWN_ERROR, 0); return -1; } if (FD_ISSET((SOCKET)osfd, &rd_wr)) { /* it's connected */ return 1; } PR_ASSERT(0); } if (_PR_PENDING_INTERRUPT(me)) { me->flags &= ~_PR_INTERRUPT; PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); rv = -1; break; } /* * We loop again if _MD_SELECT timed out and the * timeout deadline has not passed yet. */ if (rv == 0 ) { if (wait_for_remaining) { elapsed = remaining; } else { elapsed = PR_SecondsToInterval(tv.tv_sec) + PR_MicrosecondsToInterval(tv.tv_usec); } if (elapsed >= remaining) { PR_SetError(PR_IO_TIMEOUT_ERROR, 0); rv = -1; break; } else { remaining = remaining - elapsed; } } } while (rv == 0 ); break; } return(rv); } /* end socket_io_wait() */
/* void Run(); */ NS_IMETHODIMP TimerThread::Run() { nsAutoLock lock(mLock); // We need to know how many microseconds give a positive PRIntervalTime. This // is platform-dependent, we calculate it at runtime now. // First we find a value such that PR_MicrosecondsToInterval(high) = 1 PRInt32 low = 0, high = 1; while (PR_MicrosecondsToInterval(high) == 0) high <<= 1; // We now have // PR_MicrosecondsToInterval(low) = 0 // PR_MicrosecondsToInterval(high) = 1 // and we can proceed to find the critical value using binary search while (high-low > 1) { PRInt32 mid = (high+low) >> 1; if (PR_MicrosecondsToInterval(mid) == 0) low = mid; else high = mid; } // Half of the amount of microseconds needed to get positive PRIntervalTime. // We use this to decide how to round our wait times later PRInt32 halfMicrosecondsIntervalResolution = high >> 1; while (!mShutdown) { // Have to use PRIntervalTime here, since PR_WaitCondVar takes it PRIntervalTime waitFor; if (mSleeping) { // Sleep for 0.1 seconds while not firing timers. waitFor = PR_MillisecondsToInterval(100); } else { waitFor = PR_INTERVAL_NO_TIMEOUT; TimeStamp now = TimeStamp::Now(); nsTimerImpl *timer = nsnull; if (!mTimers.IsEmpty()) { timer = mTimers[0]; if (now >= timer->mTimeout + mTimeoutAdjustment) { next: // NB: AddRef before the Release under RemoveTimerInternal to avoid // mRefCnt passing through zero, in case all other refs than the one // from mTimers have gone away (the last non-mTimers[i]-ref's Release // must be racing with us, blocked in gThread->RemoveTimer waiting // for TimerThread::mLock, under nsTimerImpl::Release. NS_ADDREF(timer); RemoveTimerInternal(timer); // We release mLock around the Fire call to avoid deadlock. lock.unlock(); #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { PR_LOG(gTimerLog, PR_LOG_DEBUG, ("Timer thread woke up %fms from when it was supposed to\n", fabs((now - timer->mTimeout).ToMilliseconds()))); } #endif // We are going to let the call to PostTimerEvent here handle the // release of the timer so that we don't end up releasing the timer // on the TimerThread instead of on the thread it targets. if (NS_FAILED(timer->PostTimerEvent())) { nsrefcnt rc; NS_RELEASE2(timer, rc); // The nsITimer interface requires that its users keep a reference // to the timers they use while those timers are initialized but // have not yet fired. If this ever happens, it is a bug in the // code that created and used the timer. // // Further, note that this should never happen even with a // misbehaving user, because nsTimerImpl::Release checks for a // refcount of 1 with an armed timer (a timer whose only reference // is from the timer thread) and when it hits this will remove the // timer from the timer thread and thus destroy the last reference, // preventing this situation from occurring. NS_ASSERTION(rc != 0, "destroyed timer off its target thread!"); } timer = nsnull; lock.lock(); if (mShutdown) break; // Update now, as PostTimerEvent plus the locking may have taken a // tick or two, and we may goto next below. now = TimeStamp::Now(); } } if (!mTimers.IsEmpty()) { timer = mTimers[0]; TimeStamp timeout = timer->mTimeout + mTimeoutAdjustment; // Don't wait at all (even for PR_INTERVAL_NO_WAIT) if the next timer // is due now or overdue. // // Note that we can only sleep for integer values of a certain // resolution. We use halfMicrosecondsIntervalResolution, calculated // before, to do the optimal rounding (i.e., of how to decide what // interval is so small we should not wait at all). double microseconds = (timeout - now).ToMilliseconds()*1000; if (microseconds < halfMicrosecondsIntervalResolution) goto next; // round down; execute event now waitFor = PR_MicrosecondsToInterval(microseconds); if (waitFor == 0) waitFor = 1; // round up, wait the minimum time we can wait } #ifdef DEBUG_TIMERS if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) { if (waitFor == PR_INTERVAL_NO_TIMEOUT) PR_LOG(gTimerLog, PR_LOG_DEBUG, ("waiting for PR_INTERVAL_NO_TIMEOUT\n")); else PR_LOG(gTimerLog, PR_LOG_DEBUG, ("waiting for %u\n", PR_IntervalToMilliseconds(waitFor))); } #endif } mWaiting = PR_TRUE; PR_WaitCondVar(mCondVar, waitFor); mWaiting = PR_FALSE; } return NS_OK; }
int select(int width, fd_set *rd, fd_set *wr, fd_set *ex, struct timeval *tv) #endif { int osfd; _PRUnixPollDesc *unixpds, *unixpd, *eunixpd; PRInt32 pdcnt; PRIntervalTime timeout; int retVal; #if defined(HPUX9) || defined(AIX_RENAME_SELECT) fd_set *rd = (fd_set*) rl; fd_set *wr = (fd_set*) wl; fd_set *ex = (fd_set*) el; #endif #if 0 /* * Easy special case: zero timeout. Simply call the native * select() with no fear of blocking. */ if (tv != NULL && tv->tv_sec == 0 && tv->tv_usec == 0) { #if defined(HPUX9) || defined(AIX_RENAME_SELECT) return _MD_SELECT(width, rl, wl, el, tv); #else return _MD_SELECT(width, rd, wr, ex, tv); #endif } #endif if (!_pr_initialized) { _PR_ImplicitInitialization(); } #ifndef _PR_LOCAL_THREADS_ONLY if (_PR_IS_NATIVE_THREAD(_PR_MD_CURRENT_THREAD())) { return _MD_SELECT(width, rd, wr, ex, tv); } #endif if (width < 0 || width > FD_SETSIZE) { errno = EINVAL; return -1; } /* Compute timeout */ if (tv) { /* * These acceptable ranges for t_sec and t_usec are taken * from the select() man pages. */ if (tv->tv_sec < 0 || tv->tv_sec > 100000000 || tv->tv_usec < 0 || tv->tv_usec >= 1000000) { errno = EINVAL; return -1; } /* Convert microseconds to ticks */ timeout = PR_MicrosecondsToInterval(1000000*tv->tv_sec + tv->tv_usec); } else { /* tv being a NULL pointer means blocking indefinitely */ timeout = PR_INTERVAL_NO_TIMEOUT; } /* Check for no descriptors case (just doing a timeout) */ if ((!rd && !wr && !ex) || !width) { PR_Sleep(timeout); return 0; } /* * Set up for PR_Poll(). The PRPollDesc array is allocated * dynamically. If this turns out to have high performance * penalty, one can change to use a large PRPollDesc array * on the stack, and allocate dynamically only when it turns * out to be not large enough. * * I allocate an array of size 'width', which is the maximum * number of fds we may need to poll. */ unixpds = (_PRUnixPollDesc *) PR_CALLOC(width * sizeof(_PRUnixPollDesc)); if (!unixpds) { errno = ENOMEM; return -1; } pdcnt = 0; unixpd = unixpds; for (osfd = 0; osfd < width; osfd++) { int in_flags = 0; if (rd && FD_ISSET(osfd, rd)) { in_flags |= _PR_UNIX_POLL_READ; } if (wr && FD_ISSET(osfd, wr)) { in_flags |= _PR_UNIX_POLL_WRITE; } if (ex && FD_ISSET(osfd, ex)) { in_flags |= _PR_UNIX_POLL_EXCEPT; } if (in_flags) { unixpd->osfd = osfd; unixpd->in_flags = in_flags; unixpd->out_flags = 0; unixpd++; pdcnt++; } } /* * see comments in mozilla/cmd/xfe/mozilla.c (look for * "PR_XGetXtHackFD") */ { int needToLockXAgain; needToLockXAgain = 0; if (rd && (_pr_xt_hack_fd != -1) && FD_ISSET(_pr_xt_hack_fd, rd) && PR_XIsLocked() && (!_pr_xt_hack_okayToReleaseXLock || _pr_xt_hack_okayToReleaseXLock())) { PR_XUnlock(); needToLockXAgain = 1; } /* This is the potentially blocking step */ retVal = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); if (needToLockXAgain) { PR_XLock(); } } if (retVal > 0) { /* Compute select results */ if (rd) ZAP_SET(rd, width); if (wr) ZAP_SET(wr, width); if (ex) ZAP_SET(ex, width); /* * The return value can be either the number of ready file * descriptors or the number of set bits in the three fd_set's. */ retVal = 0; /* we're going to recompute */ eunixpd = unixpds + pdcnt; for (unixpd = unixpds; unixpd < eunixpd; unixpd++) { if (unixpd->out_flags) { int nbits = 0; /* The number of set bits on for this fd */ if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) { errno = EBADF; PR_LOG(_pr_io_lm, PR_LOG_ERROR, ("select returns EBADF for %d", unixpd->osfd)); retVal = -1; break; } /* * If a socket has a pending error, it is considered * both readable and writable. (See W. Richard Stevens, * Unix Network Programming, Vol. 1, 2nd Ed., Section 6.3, * pp. 153-154.) We also consider a socket readable if * it has a hangup condition. */ if (rd && (unixpd->in_flags & _PR_UNIX_POLL_READ) && (unixpd->out_flags & (_PR_UNIX_POLL_READ | _PR_UNIX_POLL_ERR | _PR_UNIX_POLL_HUP))) { FD_SET(unixpd->osfd, rd); nbits++; } if (wr && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) && (unixpd->out_flags & (_PR_UNIX_POLL_WRITE | _PR_UNIX_POLL_ERR))) { FD_SET(unixpd->osfd, wr); nbits++; } if (ex && (unixpd->in_flags & _PR_UNIX_POLL_WRITE) && (unixpd->out_flags & PR_POLL_EXCEPT)) { FD_SET(unixpd->osfd, ex); nbits++; } PR_ASSERT(nbits > 0); #if defined(HPUX) || defined(SOLARIS) || defined(SUNOS4) || defined(OSF1) || defined(AIX) retVal += nbits; #else /* IRIX */ retVal += 1; #endif } } } PR_ASSERT(tv || retVal != 0); PR_LOG(_pr_io_lm, PR_LOG_MIN, ("select returns %d", retVal)); PR_DELETE(unixpds); return retVal; }
SECStatus nsNSSHttpRequestSession::internal_send_receive_attempt(PRBool &retryable_error, PRPollDesc **pPollDesc, PRUint16 *http_response_code, const char **http_response_content_type, const char **http_response_headers, const char **http_response_data, PRUint32 *http_response_data_len) { if (pPollDesc) *pPollDesc = nsnull; if (http_response_code) *http_response_code = 0; if (http_response_content_type) *http_response_content_type = 0; if (http_response_headers) *http_response_headers = 0; if (http_response_data) *http_response_data = 0; PRUint32 acceptableResultSize = 0; if (http_response_data_len) { acceptableResultSize = *http_response_data_len; *http_response_data_len = 0; } if (!mListener) return SECFailure; if (NS_FAILED(mListener->InitLocks())) return SECFailure; PRLock *waitLock = mListener->mLock; PRCondVar *waitCondition = mListener->mCondition; volatile PRBool &waitFlag = mListener->mWaitFlag; waitFlag = PR_TRUE; nsRefPtr<nsHTTPDownloadEvent> event = new nsHTTPDownloadEvent; if (!event) return SECFailure; event->mListener = mListener; this->AddRef(); event->mRequestSession = this; nsresult rv = NS_DispatchToMainThread(event); if (NS_FAILED(rv)) { event->mResponsibleForDoneSignal = PR_FALSE; return SECFailure; } PRBool request_canceled = PR_FALSE; { nsAutoLock locker(waitLock); const PRIntervalTime start_time = PR_IntervalNow(); PRIntervalTime wait_interval; PRBool running_on_main_thread = NS_IsMainThread(); if (running_on_main_thread) { // let's process events quickly wait_interval = PR_MicrosecondsToInterval(50); } else { // On a secondary thread, it's fine to wait some more for // for the condition variable. wait_interval = PR_MillisecondsToInterval(250); } while (waitFlag) { if (running_on_main_thread) { // Networking runs on the main thread, which we happen to block here. // Processing events will allow the OCSP networking to run while we // are waiting. Thanks a lot to Darin Fisher for rewriting the // thread manager. Thanks a lot to Christian Biesinger who // made me aware of this possibility. (kaie) locker.unlock(); NS_ProcessNextEvent(nsnull); locker.lock(); } PR_WaitCondVar(waitCondition, wait_interval); if (!waitFlag) break; if (!request_canceled) { PRBool wantExit = nsSSLThread::exitRequested(); PRBool timeout = (PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval; if (wantExit || timeout) { request_canceled = PR_TRUE; nsRefPtr<nsCancelHTTPDownloadEvent> cancelevent = new nsCancelHTTPDownloadEvent; cancelevent->mListener = mListener; rv = NS_DispatchToMainThread(cancelevent); if (NS_FAILED(rv)) { NS_WARNING("cannot post cancel event"); } break; } } } } if (request_canceled) return SECFailure; if (NS_FAILED(mListener->mResultCode)) { if (mListener->mResultCode == NS_ERROR_CONNECTION_REFUSED || mListener->mResultCode == NS_ERROR_NET_RESET) { retryable_error = PR_TRUE; } return SECFailure; } if (http_response_code) *http_response_code = mListener->mHttpResponseCode; if (mListener->mHttpRequestSucceeded && http_response_data && http_response_data_len) { *http_response_data_len = mListener->mResultLen; // acceptableResultSize == 0 means: any size is acceptable if (acceptableResultSize != 0 && acceptableResultSize < mListener->mResultLen) { return SECFailure; } // return data by reference, result data will be valid // until "this" gets destroyed by NSS *http_response_data = (const char*)mListener->mResultData; } if (mListener->mHttpRequestSucceeded && http_response_content_type) { if (mListener->mHttpResponseContentType.Length()) { *http_response_content_type = mListener->mHttpResponseContentType.get(); } } return SECSuccess; }
JSBool TCP_read (JSContext *cx, JSObject *object, uintN argc, jsval *argv, jsval *rval) { int32 size; uint16 flags = 0; jsdouble timeout = -1; JS_BeginRequest(cx); if (argc < 1) { JS_ReportError(cx, "Not enough parameters."); JS_EndRequest(cx); return JS_FALSE; } switch (argc) { case 3: JS_ValueToNumber(cx, argv[2], &timeout); case 2: JS_ValueToUint16(cx, argv[1], &flags); case 1: JS_ValueToInt32(cx, argv[0], &size); } TCPInformation* data = (TCPInformation*) JS_GetPrivate(cx, object); jsval jsConnected; JS_GetProperty(cx, object, "connected", &jsConnected); JSBool connected; JS_ValueToBoolean(cx, jsConnected, &connected); if (!connected) { JS_ReportError(cx, "The socket isn't connected."); JS_LeaveLocalRootScope(cx); JS_EndRequest(cx); return JS_FALSE; } char* string = (char*) JS_malloc(cx, size*sizeof(char)); jsrefcount req = JS_SuspendRequest(cx); int32 offset = 0; int32 received = 0; while (offset < size) { received = PR_Recv(data->socket, (string+offset), (size-offset)*sizeof(char), flags, (timeout == -1) ? PR_INTERVAL_NO_TIMEOUT : PR_MicrosecondsToInterval(timeout*1000000)); if (received == -1) { break; } offset += received; } JS_ResumeRequest(cx, req); if (received < 0) { switch (PR_GetError()) { default: JS_ReportError(cx, "Something went wrong."); break; } JS_EndRequest(cx); return JS_FALSE; } *rval = STRING_TO_JSVAL(JS_NewString(cx, string, offset)); JS_EndRequest(cx); return JS_TRUE; }
JSBool TCP_write (JSContext* cx, JSObject* object, uintN argc, jsval* argv, jsval* rval) { JSString* stringObject; uint16 flags = 0; jsdouble timeout = -1; JS_BeginRequest(cx); if (argc < 1) { JS_ReportError(cx, "Not enough parameters."); JS_EndRequest(cx); return JS_FALSE; } JS_EnterLocalRootScope(cx); switch (argc) { case 3: JS_ValueToNumber(cx, argv[2], &timeout); case 2: JS_ValueToUint16(cx, argv[1], &flags); case 1: stringObject = JS_ValueToString(cx, argv[0]); } TCPInformation* data = (TCPInformation*) JS_GetPrivate(cx, object); jsval jsConnected; JS_GetProperty(cx, object, "connected", &jsConnected); JSBool connected; JS_ValueToBoolean(cx, jsConnected, &connected); if (!connected) { JS_ReportError(cx, "The socket isn't connected."); JS_LeaveLocalRootScope(cx); JS_EndRequest(cx); return JS_FALSE; } char* string = JS_GetStringBytes(stringObject); size_t offset = 0; int sent = 0; size_t length = JS_GetStringLength(stringObject); jsrefcount req = JS_SuspendRequest(cx); while (offset < length) { sent = PR_Send(data->socket, (string+offset), (length-offset)*sizeof(char), flags, (timeout == -1) ? PR_INTERVAL_NO_TIMEOUT : PR_MicrosecondsToInterval(timeout*1000000)); if (sent < 0) { break; } offset += sent; } JS_ResumeRequest(cx, req); JS_LeaveLocalRootScope(cx); if (sent < 0) { switch (PR_GetError()) { default: JS_ReportError(cx, "Something went wrong."); break; } JS_EndRequest(cx); return JS_FALSE; } JS_EndRequest(cx); return JS_TRUE; }