Bug 529921 browser part. Implement core support for RFC-2597/2598/3168 Quality-of-Service (DSCP) marking. r=biesi

This commit is contained in:
Philip Prindeville 2010-06-02 22:25:01 -04:00
Родитель 3d86ea7a94
Коммит 5f5392453d
17 изменённых файлов: 168 добавлений и 22 удалений

Просмотреть файл

@ -696,6 +696,25 @@ pref("network.http.pipelining.maxrequests" , 4);
// Prompt for 307 redirects
pref("network.http.prompt-temp-redirect", true);
// On networks deploying QoS, it is recommended that these be lockpref()'d,
// since inappropriate marking can easily overwhelm bandwidth reservations
// for certain services (i.e. EF for VoIP, AF4x for interactive video,
// AF3x for broadcast/streaming video, etc)
// default value for HTTP
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
// Section 4.8 "High-Throughput Data Service Class"
pref("network.http.qos", 0);
// ditto for Gopher
pref("network.gopher.qos", 0);
// default values for FTP
// in a DSCP environment this should be 40 (0x28, or AF11), per RFC-4594,
// Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
// per Section 4.7 "Low-Latency Data Service Class".
pref("network.ftp.data.qos", 0);
pref("network.ftp.control.qos", 0);
// </http>
// If false, remote JAR files that are served with a content type other than

Просмотреть файл

@ -51,7 +51,7 @@ native PRNetAddr(union PRNetAddr);
* NOTE: This is a free-threaded interface, meaning that the methods on
* this interface may be called from any thread.
*/
[scriptable, uuid(ef3f4993-cfbc-4e5a-9509-16deafe16549)]
[scriptable, uuid(19c37caa-fb41-4c32-bbf1-c6b31b75d789)]
interface nsISocketTransport : nsITransport
{
/**
@ -158,6 +158,16 @@ interface nsISocketTransport : nsITransport
*/
const unsigned long ANONYMOUS_CONNECT = (1 << 1);
/**
* Socket QoS/ToS markings. Valid values are IPTOS_DSCP_AFxx or
* IPTOS_CLASS_CSx (or IPTOS_DSCP_EF, but currently no supported
* services require expedited-forwarding).
* Not setting this value will leave the socket with the default
* ToS value, which on most systems if IPTOS_CLASS_CS0 (formerly
* IPTOS_PREC_ROUTINE).
*/
attribute octet QoSBits;
};
%{C++

Просмотреть файл

@ -719,6 +719,7 @@ nsSocketTransport::nsSocketTransport()
, mFDconnected(PR_FALSE)
, mInput(this)
, mOutput(this)
, mQoSBits(0x00)
{
LOG(("creating nsSocketTransport @%x\n", this));
@ -1141,6 +1142,12 @@ nsSocketTransport::InitiateSocket()
PR_SetSocketOption(fd, &opt);
}
if (mQoSBits) {
opt.option = PR_SockOpt_IpTypeOfService;
opt.value.tos = mQoSBits;
PR_SetSocketOption(fd, &opt);
}
// inform socket transport about this newly created socket...
rv = gSocketTransportService->AttachSocket(fd, this);
if (NS_FAILED(rv)) {
@ -1890,6 +1897,26 @@ nsSocketTransport::SetTimeout(PRUint32 type, PRUint32 value)
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::SetQoSBits(PRUint8 aQoSBits)
{
// Don't do any checking here of bits. Why? Because as of RFC-4594
// several different Class Selector and Assured Forwarding values
// have been defined, but that isn't to say more won't be added later.
// In that case, any checking would be an impediment to interoperating
// with newer QoS definitions.
mQoSBits = aQoSBits;
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::GetQoSBits(PRUint8 *aQoSBits)
{
*aQoSBits = mQoSBits;
return NS_OK;
}
NS_IMETHODIMP
nsSocketTransport::OnLookupComplete(nsICancelable *request,
nsIDNSRecord *rec,

Просмотреть файл

@ -272,6 +272,9 @@ private:
// socket timeouts are not protected by any lock.
PRUint16 mTimeouts[2];
// QoS setting for socket
PRUint8 mQoSBits;
//
// mFD access methods: called with mLock held.
//

Просмотреть файл

@ -1473,6 +1473,8 @@ nsFtpState::R_pasv() {
if (NS_FAILED(rv))
return FTP_ERROR;
mDataTransport = strans;
strans->SetQoSBits(gFtpHandler->GetDataQoSBits());
LOG(("FTP:(%x) created DT (%s:%x)\n", this, host.get(), port));

Просмотреть файл

@ -138,6 +138,8 @@ nsFtpControlConnection::Connect(nsIProxyInfo* proxyInfo,
if (NS_FAILED(rv))
return rv;
mSocket->SetQoSBits(gFtpHandler->GetControlQoSBits());
// proxy transport events back to current thread
if (eventSink)
mSocket->SetEventSink(eventSink, NS_GetCurrentThread());

Просмотреть файл

@ -88,6 +88,9 @@ PRLogModuleInfo* gFTPLog = nsnull;
#define IDLE_TIMEOUT_PREF "network.ftp.idleConnectionTimeout"
#define IDLE_CONNECTION_LIMIT 8 /* TODO pref me */
#define QOS_DATA_PREF "network.ftp.data.qos"
#define QOS_CONTROL_PREF "network.ftp.control.qos"
nsFtpProtocolHandler *gFtpHandler = nsnull;
//-----------------------------------------------------------------------------
@ -95,6 +98,8 @@ nsFtpProtocolHandler *gFtpHandler = nsnull;
nsFtpProtocolHandler::nsFtpProtocolHandler()
: mIdleTimeout(-1)
, mSessionId(0)
, mControlQoSBits(0x00)
, mDataQoSBits(0x00)
{
#if defined(PR_LOGGING)
if (!gFTPLog)
@ -134,6 +139,21 @@ nsFtpProtocolHandler::Init()
rv = branch->AddObserver(IDLE_TIMEOUT_PREF, this, PR_TRUE);
if (NS_FAILED(rv)) return rv;
PRInt32 val;
rv = branch->GetIntPref(QOS_DATA_PREF, &val);
if (NS_SUCCEEDED(rv))
mDataQoSBits = (PRUint8) NS_CLAMP(val, 0, 0xff);
rv = branch->AddObserver(QOS_DATA_PREF, this, PR_TRUE);
if (NS_FAILED(rv)) return rv;
rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
if (NS_SUCCEEDED(rv))
mControlQoSBits = (PRUint8) NS_CLAMP(val, 0, 0xff);
rv = branch->AddObserver(QOS_CONTROL_PREF, this, PR_TRUE);
if (NS_FAILED(rv)) return rv;
}
nsCOMPtr<nsIObserverService> observerService =
@ -380,10 +400,18 @@ nsFtpProtocolHandler::Observe(nsISupports *aSubject,
NS_ERROR("no prefbranch");
return NS_ERROR_UNEXPECTED;
}
PRInt32 timeout;
nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &timeout);
PRInt32 val;
nsresult rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &val);
if (NS_SUCCEEDED(rv))
mIdleTimeout = timeout;
mIdleTimeout = val;
rv = branch->GetIntPref(QOS_DATA_PREF, &val);
if (NS_SUCCEEDED(rv))
mDataQoSBits = (PRUint8) NS_CLAMP(val, 0, 0xff);
rv = branch->GetIntPref(QOS_CONTROL_PREF, &val);
if (NS_SUCCEEDED(rv))
mControlQoSBits = (PRUint8) NS_CLAMP(val, 0, 0xff);
} else if (!strcmp(aTopic, "network:offline-about-to-go-offline")) {
ClearAllConnections();
} else if (!strcmp(aTopic, "net:clear-active-logins")) {

Просмотреть файл

@ -76,6 +76,9 @@ public:
nsresult RemoveConnection(nsIURI *aKey, nsFtpControlConnection **aConn);
PRUint32 GetSessionId() { return mSessionId; }
PRUint8 GetDataQoSBits() { return mDataQoSBits; }
PRUint8 GetControlQoSBits() { return mControlQoSBits; }
private:
// Stuff for the timer callback function
struct timerStruct {
@ -111,6 +114,9 @@ private:
// control connection had been created before last "clear active logins" was
// performed.
PRUint32 mSessionId;
PRUint8 mControlQoSBits;
PRUint8 mDataQoSBits;
};
//-----------------------------------------------------------------------------

Просмотреть файл

@ -220,6 +220,8 @@ nsGopherContentStream::OpenSocket(nsIEventTarget *target)
if (NS_FAILED(rv))
return rv;
mSocket->SetQoSBits(gGopherHandler->GetQoSBits());
// Setup progress and status notifications
rv = mSocket->SetEventSink(mChannel, target);
if (NS_FAILED(rv))

Просмотреть файл

@ -46,6 +46,8 @@
#include "nsIServiceManager.h"
#include "nsIStandardURL.h"
#include "nsStandardURL.h"
#include "nsIPrefService.h"
#include "nsIPrefBranch2.h"
//-----------------------------------------------------------------------------
@ -55,6 +57,32 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsGopherHandler,
//-----------------------------------------------------------------------------
nsGopherHandler *gGopherHandler = nsnull;
nsGopherHandler::nsGopherHandler()
{
gGopherHandler = this;
}
nsGopherHandler::~nsGopherHandler()
{
gGopherHandler = nsnull;
}
PRUint8
nsGopherHandler::GetQoSBits()
{
nsresult rv;
nsCOMPtr<nsIPrefBranch2> branch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv)) {
PRInt32 val;
rv = branch->GetIntPref("network.gopher.qos", &val);
if (NS_SUCCEEDED(rv))
return NS_CLAMP(val, 0, 0xff);
}
return 0x00;
}
NS_IMETHODIMP
nsGopherHandler::GetScheme(nsACString &result)
{

Просмотреть файл

@ -53,17 +53,23 @@
{ 0x44588c1f, 0x2ce8, 0x4ad8, \
{0x9b, 0x16, 0xdf, 0xb9, 0xd9, 0xd5, 0x13, 0xa7} }
class nsGopherHandler : public nsIProxiedProtocolHandler {
class nsGopherHandler : public nsIProxiedProtocolHandler
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIPROXIEDPROTOCOLHANDLER
// nsGopherHandler methods:
nsGopherHandler() {}
nsGopherHandler();
virtual ~nsGopherHandler();
PRUint8 GetQoSBits();
protected:
nsCOMPtr<nsIProtocolProxyService> mProxySvc;
};
extern nsGopherHandler *gGopherHandler;
#endif /* nsGopherHandler_h___ */

Просмотреть файл

@ -205,10 +205,6 @@ PRTimeToSeconds(PRTime t_usec)
#define NowInSeconds() PRTimeToSeconds(PR_Now())
// ripped from glib.h
#undef CLAMP
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
// round q-value to one decimal place; return most significant digit as uint.
#define QVAL_TO_UINT(q) ((unsigned int) ((q + 0.05) * 10.0))

Просмотреть файл

@ -5104,7 +5104,7 @@ nsHttpChannel::GetPriority(PRInt32 *value)
NS_IMETHODIMP
nsHttpChannel::SetPriority(PRInt32 value)
{
PRInt16 newValue = CLAMP(value, PR_INT16_MIN, PR_INT16_MAX);
PRInt16 newValue = NS_CLAMP(value, PR_INT16_MIN, PR_INT16_MAX);
if (mPriority == newValue)
return NS_OK;
mPriority = newValue;

Просмотреть файл

@ -462,6 +462,8 @@ nsHttpConnection::CreateTransport(PRUint8 caps)
strans->SetConnectionFlags(tmpFlags);
strans->SetQoSBits(gHttpHandler->GetQoSBits());
// NOTE: these create cyclical references, which we break inside
// nsHttpConnection::Close
rv = strans->SetEventSink(this, nsnull);

Просмотреть файл

@ -172,6 +172,7 @@ nsHttpHandler::nsHttpHandler()
, mMaxPipelinedRequests(2)
, mRedirectionLimit(10)
, mPhishyUserPassLength(1)
, mQoSBits(0x00)
, mPipeliningOverSSL(PR_FALSE)
, mLastUniqueID(NowInSeconds())
, mSessionStartTime(0)
@ -934,19 +935,19 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("keep-alive.timeout"))) {
rv = prefs->GetIntPref(HTTP_PREF("keep-alive.timeout"), &val);
if (NS_SUCCEEDED(rv))
mIdleTimeout = (PRUint16) CLAMP(val, 1, 0xffff);
mIdleTimeout = (PRUint16) NS_CLAMP(val, 1, 0xffff);
}
if (PREF_CHANGED(HTTP_PREF("request.max-attempts"))) {
rv = prefs->GetIntPref(HTTP_PREF("request.max-attempts"), &val);
if (NS_SUCCEEDED(rv))
mMaxRequestAttempts = (PRUint16) CLAMP(val, 1, 0xffff);
mMaxRequestAttempts = (PRUint16) NS_CLAMP(val, 1, 0xffff);
}
if (PREF_CHANGED(HTTP_PREF("request.max-start-delay"))) {
rv = prefs->GetIntPref(HTTP_PREF("request.max-start-delay"), &val);
if (NS_SUCCEEDED(rv)) {
mMaxRequestDelay = (PRUint16) CLAMP(val, 0, 0xffff);
mMaxRequestDelay = (PRUint16) NS_CLAMP(val, 0, 0xffff);
if (mConnMgr)
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_REQUEST_DELAY,
mMaxRequestDelay);
@ -956,7 +957,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("max-connections"))) {
rv = prefs->GetIntPref(HTTP_PREF("max-connections"), &val);
if (NS_SUCCEEDED(rv)) {
mMaxConnections = (PRUint16) CLAMP(val, 1, 0xffff);
mMaxConnections = (PRUint16) NS_CLAMP(val, 1, 0xffff);
if (mConnMgr)
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS,
mMaxConnections);
@ -966,7 +967,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("max-connections-per-server"))) {
rv = prefs->GetIntPref(HTTP_PREF("max-connections-per-server"), &val);
if (NS_SUCCEEDED(rv)) {
mMaxConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff);
mMaxConnectionsPerServer = (PRUint8) NS_CLAMP(val, 1, 0xff);
if (mConnMgr) {
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_CONNECTIONS_PER_HOST,
mMaxConnectionsPerServer);
@ -979,7 +980,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-server"))) {
rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-server"), &val);
if (NS_SUCCEEDED(rv)) {
mMaxPersistentConnectionsPerServer = (PRUint8) CLAMP(val, 1, 0xff);
mMaxPersistentConnectionsPerServer = (PRUint8) NS_CLAMP(val, 1, 0xff);
if (mConnMgr)
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_HOST,
mMaxPersistentConnectionsPerServer);
@ -989,7 +990,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("max-persistent-connections-per-proxy"))) {
rv = prefs->GetIntPref(HTTP_PREF("max-persistent-connections-per-proxy"), &val);
if (NS_SUCCEEDED(rv)) {
mMaxPersistentConnectionsPerProxy = (PRUint8) CLAMP(val, 1, 0xff);
mMaxPersistentConnectionsPerProxy = (PRUint8) NS_CLAMP(val, 1, 0xff);
if (mConnMgr)
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PERSISTENT_CONNECTIONS_PER_PROXY,
mMaxPersistentConnectionsPerProxy);
@ -999,13 +1000,13 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("sendRefererHeader"))) {
rv = prefs->GetIntPref(HTTP_PREF("sendRefererHeader"), &val);
if (NS_SUCCEEDED(rv))
mReferrerLevel = (PRUint8) CLAMP(val, 0, 0xff);
mReferrerLevel = (PRUint8) NS_CLAMP(val, 0, 0xff);
}
if (PREF_CHANGED(HTTP_PREF("redirection-limit"))) {
rv = prefs->GetIntPref(HTTP_PREF("redirection-limit"), &val);
if (NS_SUCCEEDED(rv))
mRedirectionLimit = (PRUint8) CLAMP(val, 0, 0xff);
mRedirectionLimit = (PRUint8) NS_CLAMP(val, 0, 0xff);
}
if (PREF_CHANGED(HTTP_PREF("version"))) {
@ -1068,7 +1069,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("pipelining.maxrequests"))) {
rv = prefs->GetIntPref(HTTP_PREF("pipelining.maxrequests"), &val);
if (NS_SUCCEEDED(rv)) {
mMaxPipelinedRequests = CLAMP(val, 1, NS_HTTP_MAX_PIPELINED_REQUESTS);
mMaxPipelinedRequests = NS_CLAMP(val, 1, NS_HTTP_MAX_PIPELINED_REQUESTS);
if (mConnMgr)
mConnMgr->UpdateParam(nsHttpConnectionMgr::MAX_PIPELINED_REQUESTS,
mMaxPipelinedRequests);
@ -1091,6 +1092,12 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
}
}
if (PREF_CHANGED(HTTP_PREF("qos"))) {
rv = prefs->GetIntPref(HTTP_PREF("qos"), &val);
if (NS_SUCCEEDED(rv))
mQoSBits = (PRUint8) NS_CLAMP(val, 0, 0xff);
}
if (PREF_CHANGED(HTTP_PREF("sendSecureXSiteReferrer"))) {
rv = prefs->GetBoolPref(HTTP_PREF("sendSecureXSiteReferrer"), &cVar);
if (NS_SUCCEEDED(rv))
@ -1161,7 +1168,7 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
if (PREF_CHANGED(HTTP_PREF("phishy-userpass-length"))) {
rv = prefs->GetIntPref(HTTP_PREF("phishy-userpass-length"), &val);
if (NS_SUCCEEDED(rv))
mPhishyUserPassLength = (PRUint8) CLAMP(val, 0, 0xff);
mPhishyUserPassLength = (PRUint8) NS_CLAMP(val, 0, 0xff);
}
//

Просмотреть файл

@ -104,6 +104,7 @@ public:
const char *DefaultSocketType() { return mDefaultSocketType.get(); /* ok to return null */ }
nsIIDNService *IDNConverter() { return mIDNConverter; }
PRUint32 PhishyUserPassLength() { return mPhishyUserPassLength; }
PRUint8 GetQoSBits() { return mQoSBits; }
PRBool IsPersistentHttpsCachingEnabled() { return mEnablePersistentHttpsCaching; }
@ -275,6 +276,8 @@ private:
// the userpass field of the URL to obscure the actual origin server.
PRUint8 mPhishyUserPassLength;
PRUint8 mQoSBits;
PRPackedBool mPipeliningOverSSL;
nsCString mAccept;

Просмотреть файл

@ -444,6 +444,11 @@ typedef PRUint32 nsrefcnt;
#define NS_STRINGIFY_HELPER(x_) #x_
#define NS_STRINGIFY(x_) NS_STRINGIFY_HELPER(x_)
/*
* Use NS_CLAMP to force a value (such as a preference) into a range.
*/
#define NS_CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
/*
* These macros allow you to give a hint to the compiler about branch
* probability so that it can better optimize. Use them like this: