/* got new socket from accept() */ bool sbuf_accept(SBuf *sbuf, int sock, bool is_unix) { bool res; Assert(iobuf_empty(sbuf->io) && sbuf->sock == 0); AssertSanity(sbuf); sbuf->sock = sock; if (!tune_socket(sock, is_unix)) goto failed; if (!cf_reboot) { res = sbuf_wait_for_data(sbuf); if (!res) goto failed; /* socket should already have some data (linux only) */ if (cf_tcp_defer_accept && !is_unix) { sbuf_main_loop(sbuf, DO_RECV); if (!sbuf->sock) return false; } } return true; failed: sbuf_call_proto(sbuf, SBUF_EV_RECV_FAILED); return false; }
bool BlobImplSnapshot::IsSnapshot() const { AssertSanity(); return true; }
bool BlobImplSnapshot::IsWholeFile() const { AssertSanity(); return mWholeFile; }
void BlobImplSnapshot::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv) const { AssertSanity(); MOZ_ASSERT(mIsFile); aRv = mFile->GetPath(aFilename); }
NS_IMETHODIMP PermissionRequestBase::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) { AssertSanity(); MOZ_ASSERT(!strcmp(aTopic, kPermissionResponseTopic)); MOZ_ASSERT(mOwnerElement); MOZ_ASSERT(mPrincipal); nsCOMPtr<Element> element; element.swap(mOwnerElement); nsCOMPtr<nsIPrincipal> principal; mPrincipal.swap(principal); nsresult rv; uint32_t promptResult = nsDependentString(aData).ToInteger(&rv); MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv)); // The UI prompt code will only return one of these three values. We have to // transform it to our values. MOZ_ASSERT(promptResult == kPermissionDefault || promptResult == kPermissionAllowed || promptResult == kPermissionDenied); if (promptResult != kPermissionDefault) { // Save explicitly allowed or denied permissions now. SetExplicitPermission(principal, promptResult); } PermissionValue permission; switch (promptResult) { case kPermissionDefault: permission = kPermissionPrompt; break; case kPermissionAllowed: permission = kPermissionAllowed; break; case kPermissionDenied: permission = kPermissionDenied; break; default: MOZ_CRASH("Bad prompt result!"); } OnPromptComplete(permission); return NS_OK; }
/* need to connect() to get a socket */ bool sbuf_connect(SBuf *sbuf, const struct sockaddr *sa, int sa_len, int timeout_sec) { int res, sock; struct timeval timeout; bool is_unix = sa->sa_family == AF_UNIX; Assert(iobuf_empty(sbuf->io) && sbuf->sock == 0); AssertSanity(sbuf); /* * common stuff */ sock = socket(sa->sa_family, SOCK_STREAM, 0); if (sock < 0) { /* probably fd limit */ goto failed; } if (!tune_socket(sock, is_unix)) goto failed; sbuf->sock = sock; timeout.tv_sec = timeout_sec; timeout.tv_usec = 0; /* launch connection */ res = safe_connect(sock, sa, sa_len); if (res == 0) { /* unix socket gives connection immediately */ sbuf_connect_cb(sock, EV_WRITE, sbuf); return true; } else if (errno == EINPROGRESS) { /* tcp socket needs waiting */ event_set(&sbuf->ev, sock, EV_WRITE, sbuf_connect_cb, sbuf); res = event_add(&sbuf->ev, &timeout); if (res >= 0) { sbuf->wait_type = W_CONNECT; return true; } } failed: log_warning("sbuf_connect failed: %s", strerror(errno)); if (sock >= 0) safe_close(sock); sbuf->sock = 0; sbuf_call_proto(sbuf, SBUF_EV_CONNECT_FAILED); return false; }
/* * Call proto callback with proper struct MBuf. * * If callback returns true it used one of sbuf_prepare_* on sbuf, * and processing can continue. * * If it returned false it used sbuf_pause(), sbuf_close() or simply * wants to wait for next event loop (e.g. too few data available). * Callee should not touch sbuf in that case and just return to libevent. */ static bool sbuf_call_proto(SBuf *sbuf, int event) { struct MBuf mbuf; IOBuf *io = sbuf->io; bool res; AssertSanity(sbuf); Assert(event != SBUF_EV_READ || iobuf_amount_parse(io) > 0); /* if pkt callback, limit only with current packet */ if (event == SBUF_EV_PKT_CALLBACK) { iobuf_parse_limit(io, &mbuf, sbuf->pkt_remain); } else if (event == SBUF_EV_READ) { iobuf_parse_all(io, &mbuf); } else { memset(&mbuf, 0, sizeof(mbuf)); } res = sbuf->proto_cb(sbuf, event, &mbuf); AssertSanity(sbuf); Assert(event != SBUF_EV_READ || !res || sbuf->sock > 0); return res; }
nsresult PermissionRequestBase::PromptIfNeeded(PermissionValue* aCurrentValue) { AssertSanity(); MOZ_ASSERT(aCurrentValue); MOZ_ASSERT(mPrincipal); // Tricky, we want to release the window and principal in all cases except // when we successfully prompt. nsCOMPtr<Element> element; mOwnerElement.swap(element); nsCOMPtr<nsIPrincipal> principal; mPrincipal.swap(principal); PermissionValue currentValue; nsresult rv = GetCurrentPermission(principal, ¤tValue); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } MOZ_ASSERT(currentValue != kPermissionDefault); if (currentValue == kPermissionPrompt) { nsCOMPtr<nsIObserverService> obsSvc = GetObserverService(); if (NS_WARN_IF(!obsSvc)) { return NS_ERROR_FAILURE; } // We're about to prompt so swap the members back. element.swap(mOwnerElement); principal.swap(mPrincipal); rv = obsSvc->NotifyObservers(static_cast<nsIObserver*>(this), kPermissionPromptTopic, nullptr); if (NS_WARN_IF(NS_FAILED(rv))) { // Finally release if we failed the prompt. mOwnerElement = nullptr; mPrincipal = nullptr; return rv; } } *aCurrentValue = currentValue; return NS_OK; }
NS_IMETHODIMP PermissionRequestBase::GetInterface(const nsIID& aIID, void** aResult) { AssertSanity(); if (aIID.Equals(NS_GET_IID(nsIObserver))) { return QueryInterface(aIID, aResult); } if (aIID.Equals(NS_GET_IID(nsIDOMNode)) && mOwnerElement) { return mOwnerElement->QueryInterface(aIID, aResult); } *aResult = nullptr; return NS_ERROR_NOT_AVAILABLE; }
void PermissionRequestBase::SetExplicitPermission(nsIPrincipal* aPrincipal, uint32_t aIntPermission) { AssertSanity(); MOZ_ASSERT(aPrincipal); MOZ_ASSERT(aIntPermission == kPermissionAllowed || aIntPermission == kPermissionDenied); nsCOMPtr<nsIPermissionManager> permMan = GetPermissionManager(); if (NS_WARN_IF(!permMan)) { return; } nsresult rv = permMan->AddFromPrincipal(aPrincipal, kPermissionString, aIntPermission, nsIPermissionManager::EXPIRE_NEVER, /* aExpireTime */ 0); if (NS_WARN_IF(NS_FAILED(rv))) { return; } }
/* libevent EV_WRITE: called when dest socket is writable again */ static void sbuf_send_cb(int sock, short flags, void *arg) { SBuf *sbuf = arg; bool res; /* sbuf was closed before in this loop */ if (!sbuf->sock) return; AssertSanity(sbuf); Assert(sbuf->wait_type == W_SEND); sbuf->wait_type = W_NONE; /* prepare normal situation for sbuf_main_loop */ res = sbuf_wait_for_data(sbuf); if (res) { /* here we should certainly skip recv() */ sbuf_main_loop(sbuf, SKIP_RECV); } else { /* drop if problems */ sbuf_call_proto(sbuf, SBUF_EV_SEND_FAILED); } }
/* * Main recv-parse-send-repeat loop. * * Reason for skip_recv is to avoid extra recv(). The problem with it * is EOF from socket. Currently that means that the pending data is * dropped. Fortunately server sockets are not paused and dropping * data from client is no problem. So only place where skip_recv is * important is sbuf_send_cb(). */ static void sbuf_main_loop(SBuf *sbuf, bool skip_recv) { unsigned free, ok; int loopcnt = 0; /* sbuf was closed before in this event loop */ if (!sbuf->sock) return; /* reading should be disabled when waiting */ Assert(sbuf->wait_type == W_RECV); AssertSanity(sbuf); if (!allocate_iobuf(sbuf)) return; /* avoid recv() if asked */ if (skip_recv) goto skip_recv; try_more: /* make room in buffer */ sbuf_try_resync(sbuf, false); /* avoid spending too much time on single socket */ if (cf_sbuf_loopcnt > 0 && loopcnt >= cf_sbuf_loopcnt) { log_debug("loopcnt full"); /* * sbuf_process_pending() avoids some data if buffer is full, * but as we exit processing loop here, we need to retry * after resync to process all data. (result is ignored) */ ok = sbuf_process_pending(sbuf); return; } loopcnt++; /* * here used to be if (free > SBUF_SMALL_PKT) check * but with skip_recv switch its should not be needed anymore. */ free = iobuf_amount_recv(sbuf->io); if (free > 0) { /* * When suspending, try to hit packet boundary ASAP. */ if (cf_pause_mode == P_SUSPEND && sbuf->pkt_remain > 0 && sbuf->pkt_remain < free) { free = sbuf->pkt_remain; } /* now fetch the data */ ok = sbuf_actual_recv(sbuf, free); if (!ok) return; } skip_recv: /* now handle it */ ok = sbuf_process_pending(sbuf); if (!ok) return; /* if the buffer is full, there can be more data available */ if (iobuf_amount_recv(sbuf->io) <= 0) goto try_more; /* clean buffer */ sbuf_try_resync(sbuf, true); /* notify proto that all is sent */ if (sbuf_is_empty(sbuf)) sbuf_call_proto(sbuf, SBUF_EV_FLUSH); }