diff --git a/mozilla/directory/xpcom/base/src/nsLDAPConnection.cpp b/mozilla/directory/xpcom/base/src/nsLDAPConnection.cpp index 1b80f2346ba..ce6e48d8eb5 100644 --- a/mozilla/directory/xpcom/base/src/nsLDAPConnection.cpp +++ b/mozilla/directory/xpcom/base/src/nsLDAPConnection.cpp @@ -49,7 +49,8 @@ #include "nsIDNSService.h" #include "nsIRequestObserver.h" #include "nsIProxyObjectManager.h" -#include "netCore.h" +#include "nsEventQueueUtils.h" +#include "nsNetError.h" const char kConsoleServiceContractId[] = "@mozilla.org/consoleservice;1"; const char kDNSServiceContractId[] = "@mozilla.org/network/dns-service;1"; @@ -62,8 +63,7 @@ nsLDAPConnection::nsLDAPConnection() mPendingOperations(0), mRunnable(0), mSSL(PR_FALSE), - mDNSRequest(0), - mDNSFinished(PR_FALSE) + mDNSRequest(0) { } @@ -100,7 +100,7 @@ nsLDAPConnection::~nsLDAPConnection() // Init listener (if still there). // if (mDNSRequest) { - mDNSRequest->Cancel(NS_BINDING_ABORTED); + mDNSRequest->Cancel(); mDNSRequest = 0; } mInitListener = 0; @@ -209,20 +209,11 @@ nsLDAPConnection::Init(const char *aHost, PRInt16 aPort, PRBool aSSL, return NS_ERROR_FAILURE; } - // Get a proxy object so the callback happens on the current thread. - // This is now a Synchronous proxy, due to the fact that the DNS - // service hands out data which it later deallocates, and the async - // proxy makes this unreliable. See bug 102227 for more details. - // - rv = NS_GetProxyForObject(NS_CURRENT_EVENTQ, - NS_GET_IID(nsIDNSListener), - NS_STATIC_CAST(nsIDNSListener*, this), - PROXY_SYNC | PROXY_ALWAYS, - getter_AddRefs(selfProxy)); - + nsCOMPtr curEventQ; + rv = NS_GetCurrentEventQ(getter_AddRefs(curEventQ)); if (NS_FAILED(rv)) { NS_ERROR("nsLDAPConnection::Init(): couldn't " - "create proxy to this object for callback"); + "get current event queue"); return NS_ERROR_FAILURE; } @@ -242,10 +233,10 @@ nsLDAPConnection::Init(const char *aHost, PRInt16 aPort, PRBool aSSL, return NS_ERROR_FAILURE; } - rv = pDNSService->Lookup(aHost, - selfProxy, - nsnull, - getter_AddRefs(mDNSRequest)); + mDNSHost = aHost; + rv = pDNSService->AsyncResolve(mDNSHost, + PR_FALSE, this, curEventQ, + getter_AddRefs(mDNSRequest)); if (NS_FAILED(rv)) { switch (rv) { @@ -253,24 +244,14 @@ nsLDAPConnection::Init(const char *aHost, PRInt16 aPort, PRBool aSSL, case NS_ERROR_UNKNOWN_HOST: case NS_ERROR_FAILURE: case NS_ERROR_OFFLINE: - return rv; + break; default: - return NS_ERROR_UNEXPECTED; + rv = NS_ERROR_UNEXPECTED; } + mDNSHost.Truncate(); } - - // The DNS service can actually call the listeners even before the - // Lookup() function has returned. If that happens, we can still hold - // a reference to the DNS request, even after the DNS lookup is done. - // If this happens, lets just get rid of the DNS request, since we won't - // need it any more. - // - if (mDNSFinished && mDNSRequest) { - mDNSRequest = 0; - } - - return NS_OK; + return rv; } NS_IMETHODIMP @@ -823,102 +804,50 @@ nsLDAPConnectionLoop::Run(void) return NS_OK; } -// -// nsIDNSListener implementation, for asynchronous DNS. Once the lookup -// has finished, we will initialize the LDAP connection properly. -// NS_IMETHODIMP -nsLDAPConnection::OnStartLookup(nsISupports *aContext, const char *aHostName) -{ - // Initialize some members which will be used in the other callbacks. - // - mDNSStatus = NS_OK; - mResolvedIP = ""; - - return NS_OK; -} - -NS_IMETHODIMP -nsLDAPConnection::OnFound(nsISupports *aContext, - const char* aHostName, - nsHostEnt *aHostEnt) -{ - PRUint32 index = 0; - PRNetAddr netAddress; - char addrbuf[64]; - - // Do we have a proper host entry? If not, set the internal DNS - // status to indicate that host lookup failed. - // - if (!aHostEnt->hostEnt.h_addr_list || !aHostEnt->hostEnt.h_addr_list[0]) { - mDNSStatus = NS_ERROR_UNKNOWN_HOST; - - return NS_ERROR_UNKNOWN_HOST; - } - - // Make sure our address structure is initialized properly - // - memset(&netAddress, 0, sizeof(netAddress)); - PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, &netAddress); - - // Loop through the addresses, and add them to our IP string. - // - while (aHostEnt->hostEnt.h_addr_list[index]) { - if (aHostEnt->hostEnt.h_addrtype == PR_AF_INET6) { - memcpy(&netAddress.ipv6.ip, aHostEnt->hostEnt.h_addr_list[index], - sizeof(netAddress.ipv6.ip)); - } else { - // Can this ever happen? Not sure, cause everything seems to be - // IPv6 internally, even in the DNS service. - // - PR_ConvertIPv4AddrToIPv6(*(PRUint32*)aHostEnt->hostEnt.h_addr_list[0], - &netAddress.ipv6.ip); - } - if (PR_IsNetAddrType(&netAddress, PR_IpAddrV4Mapped)) { - // If there are more IPs in the list, we separate them with - // a space, as supported/used by the LDAP C-SDK. - // - if (index) - mResolvedIP.Append(' '); - - // Convert the IPv4 address to a string, and append it to our - // list of IPs. - // - PR_NetAddrToString(&netAddress, addrbuf, sizeof(addrbuf)); - if ((addrbuf[0] == ':') && (strlen(addrbuf) > 7)) - mResolvedIP.Append(addrbuf+7); - else - mResolvedIP.Append(addrbuf); - } - index++; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsLDAPConnection::OnStopLookup(nsISupports *aContext, - const char *aHostName, - nsresult aStatus) -{ - nsCOMPtr selfProxy; +nsLDAPConnection::OnLookupComplete(nsIDNSRequest *aRequest, + nsIDNSRecord *aRecord, + nsresult aStatus) +{ nsresult rv = NS_OK; - if (NS_FAILED(mDNSStatus)) { - // We failed previously in the OnFound() callback + if (aRecord) { + // Build mResolvedIP list // - switch (mDNSStatus) { - case NS_ERROR_UNKNOWN_HOST: - case NS_ERROR_FAILURE: - rv = mDNSStatus; - break; + mResolvedIP.Truncate(); - default: - rv = NS_ERROR_UNEXPECTED; - break; + PRInt32 index = 0; + char addrbuf[64]; + PRNetAddr addr; + + while (NS_SUCCEEDED(aRecord->GetNextAddr(0, &addr))) { + // We can only use v4 addresses + // + PRBool v4mapped = PR_FALSE; + if (addr.raw.family == PR_AF_INET6) + v4mapped = PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped); + if (addr.raw.family == PR_AF_INET || v4mapped) { + // If there are more IPs in the list, we separate them with + // a space, as supported/used by the LDAP C-SDK. + // + if (index++) + mResolvedIP.Append(' '); + + // Convert the IPv4 address to a string, and append it to our + // list of IPs. Strip leading '::FFFF:' (the IPv4-mapped-IPv6 + // indicator) if present. + // + PR_NetAddrToString(&addr, addrbuf, sizeof(addrbuf)); + if ((addrbuf[0] == ':') && (strlen(addrbuf) > 7)) + mResolvedIP.Append(addrbuf+7); + else + mResolvedIP.Append(addrbuf); + } } - } else if (NS_FAILED(aStatus)) { - // The DNS service failed , lets pass something reasonable + } + + if (NS_FAILED(aStatus)) { + // The DNS service failed, lets pass something reasonable // back to the listener. // switch (aStatus) { @@ -977,7 +906,7 @@ nsLDAPConnection::OnStopLookup(nsISupports *aContext, rv = NS_ERROR_UNEXPECTED; } - rv = nsLDAPInstallSSL(mConnectionHandle, aHostName); + rv = nsLDAPInstallSSL(mConnectionHandle, mDNSHost.get()); if (NS_FAILED(rv)) { NS_ERROR("nsLDAPConnection::OnStopLookup(): Error installing" " secure LDAP routines for connection"); @@ -1023,7 +952,7 @@ nsLDAPConnection::OnStopLookup(nsISupports *aContext, // indicating that DNS has finished. // mDNSRequest = 0; - mDNSFinished = PR_TRUE; + mDNSHost.Truncate(); // Call the listener, and then we can release our reference to it. // diff --git a/mozilla/directory/xpcom/base/src/nsLDAPConnection.h b/mozilla/directory/xpcom/base/src/nsLDAPConnection.h index cb5c2da30ba..66458390622 100644 --- a/mozilla/directory/xpcom/base/src/nsLDAPConnection.h +++ b/mozilla/directory/xpcom/base/src/nsLDAPConnection.h @@ -47,7 +47,7 @@ #include "nspr.h" #include "nsWeakReference.h" #include "nsWeakPtr.h" -#include "nsIDNSListener.h" +#include "nsIDNSService.h" #include "nsIRequest.h" // 0d871e30-1dd2-11b2-8ea9-831778c78e93 @@ -124,10 +124,9 @@ class nsLDAPConnection : public nsILDAPConnection, nsCString mResolvedIP; // Preresolved list of host IPs nsCOMPtr mInitListener; // Init callback - nsCOMPtr mDNSRequest; // The "active" DNS request + nsCOMPtr mDNSRequest; // The "active" DNS request + nsCString mDNSHost; // The hostname being resolved nsCOMPtr mClosure; // private parameter (anything caller desires) - nsresult mDNSStatus; // The status of DNS lookup (rv cache) - PRBool mDNSFinished; // Flag if DNS lookup has finished }; // This class implements the nsIRunnable interface, in this case just a diff --git a/mozilla/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp b/mozilla/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp index 23d7a947c9a..954af287c74 100644 --- a/mozilla/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp +++ b/mozilla/directory/xpcom/base/src/nsLDAPSecurityGlue.cpp @@ -193,7 +193,8 @@ nsLDAPSSLConnect(const char *hostlist, int defport, int timeout, // clear, and I suspect it may depend on the format of the name in // the certificate. Need to investigate. // - rv = tlsSocketProvider->AddToSocket(sessionClosure->hostname, defport, + rv = tlsSocketProvider->AddToSocket(PR_AF_INET, + sessionClosure->hostname, defport, nsnull, 0, socketInfo.soinfo_prfd, getter_AddRefs(securityInfo)); if (NS_FAILED(rv)) { diff --git a/mozilla/extensions/webservices/security/src/nsWSAUtils.cpp b/mozilla/extensions/webservices/security/src/nsWSAUtils.cpp index 6134f7dde8a..10a2df695d2 100755 --- a/mozilla/extensions/webservices/security/src/nsWSAUtils.cpp +++ b/mozilla/extensions/webservices/security/src/nsWSAUtils.cpp @@ -45,6 +45,7 @@ #include "nsIRequest.h" #include "nsEventQueueUtils.h" #include "nsAutoPtr.h" +#include "nsNetCID.h" static const char kSecurityProperties[] = "chrome://communicator/locale/webservices/security.properties"; @@ -230,14 +231,14 @@ nsWSAUtils::GetOfficialHostName(nsIURI* aServiceURI, if (NS_FAILED(rv)) return rv; - nsXPIDLCString host; + nsCAutoString host; aServiceURI->GetHost(host); nsRefPtr listener = new nsDNSListener(); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); - nsCOMPtr dummy; - rv = dns->Lookup(host, listener, nsnull, getter_AddRefs(dummy)); + nsCOMPtr dummy; + rv = dns->AsyncResolve(host, PR_FALSE, listener, nsnull, getter_AddRefs(dummy)); if (NS_FAILED(rv)) return rv; @@ -292,26 +293,13 @@ nsDNSListener::~nsDNSListener() } NS_IMETHODIMP -nsDNSListener::OnStartLookup(nsISupports* aContext, const char* aHost) +nsDNSListener::OnLookupComplete(nsIDNSRequest* aRequest, + nsIDNSRecord* aRecord, + nsresult aStatus) { - return NS_OK; -} + if (aRecord) + aRecord->GetCanonicalName(mOfficialHostName); -NS_IMETHODIMP -nsDNSListener::OnFound(nsISupports* aContext, - const char* aHost, - nsHostEnt* aHostEnt) -{ - if (aHostEnt) - mOfficialHostName.Assign(aHostEnt->hostEnt.h_name); - return NS_OK; -} - -NS_IMETHODIMP -nsDNSListener::OnStopLookup(nsISupports* aContext, - const char* aHost, - nsresult aStatus) -{ // Post an event to the UI thread's event queue to cause // ProcessPendingEvents to run. nsCOMPtr uiEventQ; diff --git a/mozilla/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp b/mozilla/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp index d48fd1f256b..b9da18bb74a 100644 --- a/mozilla/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp +++ b/mozilla/mailnews/addrbook/src/nsAbLDAPAutoCompFormatter.cpp @@ -40,6 +40,7 @@ #include "nsXPCOM.h" #include "nsISupportsPrimitives.h" #include "nsIDNSService.h" +#include "nsNetError.h" NS_IMPL_ISUPPORTS2(nsAbLDAPAutoCompFormatter, nsILDAPAutoCompFormatter, diff --git a/mozilla/netwerk/base/public/nsISocketTransport.idl b/mozilla/netwerk/base/public/nsISocketTransport.idl index 120575c6347..49850ad4bae 100644 --- a/mozilla/netwerk/base/public/nsISocketTransport.idl +++ b/mozilla/netwerk/base/public/nsISocketTransport.idl @@ -40,11 +40,7 @@ interface nsIInterfaceRequestor; interface nsISocketEventSink; -%{C++ -#include "prio.h" -%} - -[ptr] native PRNetAddrStar(PRNetAddr); +[ptr] native PRNetAddrStar(union PRNetAddr); /** * nsISocketTransport @@ -64,10 +60,11 @@ interface nsISocketTransport : nsITransport */ readonly attribute long port; - /** - * Get the PRNetAddr for the underlying socket connection. + /** + * Returns the IP address for the underlying socket connection. This + * attribute is only defined once a connection has been established. */ - [noscript] void getAddress(in PRNetAddrStar addr); + [noscript] void getAddress(in PRNetAddrStar netAddr); /** * Security info object returned from the PSM socket provider. This object diff --git a/mozilla/netwerk/base/public/nsNetError.h b/mozilla/netwerk/base/public/nsNetError.h index cbbc24c4c9c..755f67e08b0 100644 --- a/mozilla/netwerk/base/public/nsNetError.h +++ b/mozilla/netwerk/base/public/nsNetError.h @@ -254,6 +254,23 @@ NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 42) +/****************************************************************************** + * Socket specific error codes: + */ + +/** + * The specified socket type does not exist. + */ +#define NS_ERROR_UNKNOWN_SOCKET_TYPE \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 51) + +/** + * The specified socket type could not be created. + */ +#define NS_ERROR_SOCKET_CREATE_FAILED \ + NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 52) + + /****************************************************************************** * Cache specific error codes: * diff --git a/mozilla/netwerk/base/src/nsProxyAutoConfig.js b/mozilla/netwerk/base/src/nsProxyAutoConfig.js index de679e78d7d..a317e82ae71 100644 --- a/mozilla/netwerk/base/src/nsProxyAutoConfig.js +++ b/mozilla/netwerk/base/src/nsProxyAutoConfig.js @@ -121,7 +121,7 @@ nsProxyAutoConfig.prototype = { // evaluate loded js file evalInSandbox(mypac, ProxySandBox, pacURL); try { - ProxySandBox.myIP = dns.myIPAddress; + ProxySandBox.myIP = dns.resolve(dns.myHostName, false).getNextAddrAsString(); } catch (e) { // Well, theres nothing better. // see bugs 80363 and 92516. @@ -149,7 +149,7 @@ function dnsResolve(host) { return dnsResolveCachedIp; } try { - dnsResolveCachedIp = dns.resolve(host); + dnsResolveCachedIp = dns.resolve(host, false).getNextAddrAsString(); dnsResolveCachedHost = host; } catch (e) { diff --git a/mozilla/netwerk/base/src/nsSocketTransport2.cpp b/mozilla/netwerk/base/src/nsSocketTransport2.cpp index 3221301bf86..e36d6efada7 100644 --- a/mozilla/netwerk/base/src/nsSocketTransport2.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransport2.cpp @@ -50,6 +50,7 @@ #include "prmem.h" #include "pratom.h" #include "plstr.h" +#include "prnetdb.h" #include "prerror.h" #include "prerr.h" @@ -58,7 +59,6 @@ #include "nsISocketProviderService.h" #include "nsISocketProvider.h" #include "nsISSLSocketControl.h" -#include "nsIDNSService.h" #include "nsIProxyInfo.h" #include "nsIPipe.h" @@ -91,7 +91,7 @@ static PRErrorCode RandomizeConnectError(PRErrorCode code) errors[] = { // // These errors should be recoverable provided there is another - // IP address in mNetAddrList. + // IP address in mDNSRecord. // { PR_CONNECT_REFUSED_ERROR, "PR_CONNECT_REFUSED_ERROR" }, { PR_CONNECT_TIMEOUT_ERROR, "PR_CONNECT_TIMEOUT_ERROR" }, @@ -612,7 +612,6 @@ nsSocketTransport::nsSocketTransport() , mFDconnected(PR_FALSE) , mInput(this) , mOutput(this) - , mNetAddr(nsnull) { LOG(("creating nsSocketTransport @%x\n", this)); @@ -735,36 +734,12 @@ nsSocketTransport::ResolveHost() nsresult rv; - PRIPv6Addr addr; - rv = gSocketTransportService->LookupHost(SocketHost(), SocketPort(), &addr); + nsCOMPtr dns = do_GetService(kDNSServiceCID, &rv); + if (NS_FAILED(rv)) return rv; + + rv = dns->AsyncResolve(SocketHost(), PR_FALSE, this, nsnull, + getter_AddRefs(mDNSRequest)); if (NS_SUCCEEDED(rv)) { - // found address! - mNetAddrList.Init(1); - mNetAddr = mNetAddrList.GetNext(nsnull); - PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, SocketPort(), mNetAddr); - memcpy(&mNetAddr->ipv6.ip, &addr, sizeof(addr)); -#ifdef PR_LOGGING - if (LOG_ENABLED()) { - char buf[128]; - PR_NetAddrToString(mNetAddr, buf, sizeof(buf)); - LOG((" -> using cached ip address [%s]\n", buf)); - } -#endif - // suppress resolving status message since we are bypassing that step. - mState = STATE_RESOLVING; - rv = gSocketTransportService->PostEvent(this, - MSG_DNS_LOOKUP_COMPLETE, - NS_OK, nsnull); - } - else { - const char *host = SocketHost().get(); - - nsCOMPtr dns = do_GetService(kDNSServiceCID, &rv); - if (NS_FAILED(rv)) return rv; - - rv = dns->Lookup(host, this, nsnull, getter_AddRefs(mDNSRequest)); - if (NS_FAILED(rv)) return rv; - LOG((" advancing to STATE_RESOLVING\n")); mState = STATE_RESOLVING; SendStatus(STATUS_RESOLVING); @@ -783,7 +758,7 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, PRBool &proxyTransparent, PRBool usingSSL = PR_FALSE; if (mTypeCount == 0) { - fd = PR_OpenTCPSocket(PR_AF_INET6); + fd = PR_OpenTCPSocket(mNetAddr.raw.family); rv = fd ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } else { @@ -812,7 +787,8 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, PRBool &proxyTransparent, PRBool if (i == 0) { // if this is the first type, we'll want the // service to allocate a new socket - rv = provider->NewSocket(host, port, proxyHost, proxyPort, + rv = provider->NewSocket(mNetAddr.raw.family, + host, port, proxyHost, proxyPort, &fd, getter_AddRefs(secinfo)); if (NS_SUCCEEDED(rv) && !fd) { @@ -824,7 +800,8 @@ nsSocketTransport::BuildSocket(PRFileDesc *&fd, PRBool &proxyTransparent, PRBool // the socket has already been allocated, // so we just want the service to add itself // to the stack (such as pushing an io layer) - rv = provider->AddToSocket(host, port, proxyHost, proxyPort, + rv = provider->AddToSocket(mNetAddr.raw.family, + host, port, proxyHost, proxyPort, fd, getter_AddRefs(secinfo)); } if (NS_FAILED(rv)) @@ -931,10 +908,18 @@ nsSocketTransport::InitiateSocket() mState = STATE_CONNECTING; SendStatus(STATUS_CONNECTING_TO); +#if defined(PR_LOGGING) + if (LOG_ENABLED()) { + char buf[64]; + PR_NetAddrToString(&mNetAddr, buf, sizeof(buf)); + LOG((" trying address: %s\n", buf)); + } +#endif + // // Initiate the connect() to the host... // - status = PR_Connect(fd, mNetAddr, NS_SOCKET_CONNECT_TIMEOUT); + status = PR_Connect(fd, &mNetAddr, NS_SOCKET_CONNECT_TIMEOUT); if (status == PR_SUCCESS) { // // we are connected! @@ -1017,17 +1002,10 @@ nsSocketTransport::RecoverFromError() PRBool tryAgain = PR_FALSE; // try next ip address only if past the resolver stage... - if (mState == STATE_CONNECTING) { - PRNetAddr *nextAddr = mNetAddrList.GetNext(mNetAddr); - if (nextAddr) { - mNetAddr = nextAddr; -#if defined(PR_LOGGING) - if (LOG_ENABLED()) { - char buf[64]; - PR_NetAddrToString(mNetAddr, buf, sizeof(buf)); - LOG((" ...trying next address: %s\n", buf)); - } -#endif + if (mState == STATE_CONNECTING && mDNSRecord) { + nsresult rv = mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr); + if (NS_SUCCEEDED(rv)) { + LOG((" trying again with next ip address\n")); tryAgain = PR_TRUE; } } @@ -1123,9 +1101,6 @@ nsSocketTransport::OnSocketConnected() NS_ASSERTION(mFDref == 1, "wrong socket ref count"); mFDconnected = PR_TRUE; } - - gSocketTransportService->RememberHost(SocketHost(), SocketPort(), - &mNetAddr->ipv6.ip); } PRFileDesc * @@ -1189,6 +1164,12 @@ nsSocketTransport::OnSocketEvent(PRUint32 type, PRUint32 uparam, void *vparam) case MSG_DNS_LOOKUP_COMPLETE: LOG((" MSG_DNS_LOOKUP_COMPLETE\n")); mDNSRequest = 0; + if (vparam) { + nsIDNSRecord *rec = NS_REINTERPRET_CAST(nsIDNSRecord *, vparam); + mDNSRecord = rec; + NS_RELEASE(rec); + mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr); + } // uparam contains DNS lookup status if (NS_FAILED(uparam)) { // fixup error code if proxy was not found @@ -1323,7 +1304,7 @@ nsSocketTransport::OnSocketDetached(PRFileDesc *fd) // make sure there isn't any pending DNS request if (mDNSRequest) { - mDNSRequest->Cancel(mCondition); + mDNSRequest->Cancel(); mDNSRequest = 0; } @@ -1559,128 +1540,37 @@ nsSocketTransport::GetPort(PRInt32 *port) NS_IMETHODIMP nsSocketTransport::GetAddress(PRNetAddr *addr) { - // - // NOTE: mNetAddr is assigned on either the socket thread or the DNS thread. - // assuming pointer assignment is atomic, this code does not need any - // locks to maintain thread safety. - // + // once we are in the connected state, mNetAddr will not change. + // so if we can verify that we are in the connected state, then + // we can freely access mNetAddr from any thread without being + // inside a critical section. - if (!mNetAddr) - return NS_ERROR_NOT_AVAILABLE; - - memcpy(addr, mNetAddr, sizeof(PRNetAddr)); + NS_ENSURE_TRUE(mState == STATE_TRANSFERRING, NS_ERROR_NOT_AVAILABLE); + + memcpy(addr, &mNetAddr, sizeof(mNetAddr)); return NS_OK; } NS_IMETHODIMP -nsSocketTransport::OnStartLookup(nsISupports *ctx, const char *host) +nsSocketTransport::OnLookupComplete(nsIDNSRequest *request, + nsIDNSRecord *rec, + nsresult status) { - return NS_OK; -} - -NS_IMETHODIMP -nsSocketTransport::OnFound(nsISupports *ctx, - const char *host, - nsHostEnt *hostEnt) -{ - // no locking should be required... yes, we are running on the DNS - // thread, but our state variables we're going to touch will not be - // touched by anyone else until we post a MSG_DNS_LOOKUP_COMPLETE - // event, or until the socket transports destructor runs. - - char **addrList = hostEnt->hostEnt.h_addr_list; - - if (addrList && addrList[0]) { - PRUint32 len = 0; - PRUint16 port = SocketPort(); - - LOG(("nsSocketTransport::OnFound [%s:%hu this=%x] lookup succeeded [FQDN=%s]\n", - host, port, this, hostEnt->hostEnt.h_name)); - - // determine the number of address in the list - for (; *addrList; ++addrList) - ++len; - addrList -= len; - - // allocate space for the addresses - mNetAddrList.Init(len); - - // populate the address list - PRNetAddr *addr = nsnull; - while ((addr = mNetAddrList.GetNext(addr)) != nsnull) { - PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, port, addr); - if (hostEnt->hostEnt.h_addrtype == PR_AF_INET6) - memcpy(&addr->ipv6.ip, *addrList, sizeof(addr->ipv6.ip)); - else - PR_ConvertIPv4AddrToIPv6(*(PRUint32 *)(*addrList), &addr->ipv6.ip); - ++addrList; -#if defined(PR_LOGGING) - if (LOG_ENABLED()) { - char buf[50]; - PR_NetAddrToString(addr, buf, sizeof(buf)); - LOG((" => %s\n", buf)); - } -#endif - } - - // start with first address in list - mNetAddr = mNetAddrList.GetNext(nsnull); - } - return NS_OK; -} - -NS_IMETHODIMP -nsSocketTransport::OnStopLookup(nsISupports *ctx, const char *host, - nsresult status) -{ - LOG(("nsSocketTransport::OnStopLookup [this=%x status=%x]\n", - this, status)); - - // keep the DNS service honest... - if (NS_SUCCEEDED(status) && (mNetAddr == nsnull)) { - NS_ERROR("success without a result"); - status = NS_ERROR_UNEXPECTED; - } + // event handler will release this reference. + NS_IF_ADDREF(rec); nsresult rv = gSocketTransportService->PostEvent(this, MSG_DNS_LOOKUP_COMPLETE, - status, nsnull); + status, rec); // if posting a message fails, then we should assume that the socket // transport has been shutdown. this should never happen! if it does // it means that the socket transport service was shutdown before the // DNS service. - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { NS_WARNING("unable to post DNS lookup complete message"); + NS_IF_RELEASE(rec); + } return NS_OK; } - -//----------------------------------------------------------------------------- -// nsSocketTransport::NetAddrList -//----------------------------------------------------------------------------- - -nsresult -nsSocketTransport::NetAddrList::Init(PRUint32 len) -{ - NS_ASSERTION(!mList, "already initialized"); - mList = new PRNetAddr[len]; - if (!mList) - return NS_ERROR_OUT_OF_MEMORY; - mLen = len; - return NS_OK; -} - -PRNetAddr * -nsSocketTransport::NetAddrList::GetNext(PRNetAddr *addr) -{ - if (!addr) - return mList; - - PRUint32 offset = addr - mList; - NS_ASSERTION(offset < mLen, "invalid address"); - if (offset + 1 < mLen) - return addr + 1; - - return nsnull; -} diff --git a/mozilla/netwerk/base/src/nsSocketTransport2.h b/mozilla/netwerk/base/src/nsSocketTransport2.h index b5383f28e14..85e4fa1c492 100644 --- a/mozilla/netwerk/base/src/nsSocketTransport2.h +++ b/mozilla/netwerk/base/src/nsSocketTransport2.h @@ -46,8 +46,7 @@ #include "nsIInterfaceRequestor.h" #include "nsIAsyncInputStream.h" #include "nsIAsyncOutputStream.h" -#include "nsIDNSListener.h" -#include "nsIRequest.h" +#include "nsIDNSService.h" class nsSocketTransport; @@ -164,24 +163,6 @@ private: STATE_TRANSFERRING }; - class NetAddrList { - public: - NetAddrList() : mList(nsnull), mLen(0) {} - ~NetAddrList() { delete[] mList; } - - // allocate space for the address list - nsresult Init(PRUint32 len); - - // given a net addr in the list, return the next addr. - // if given NULL, then return the first addr in the list. - // returns NULL if given addr is the last addr. - PRNetAddr *GetNext(PRNetAddr *currentAddr); - - private: - PRNetAddr *mList; - PRUint32 mLen; - }; - //------------------------------------------------------------------------- // these members are "set" at initialization time and are never modified // afterwards. this allows them to be safely accessed from any thread. @@ -210,7 +191,9 @@ private: PRPackedBool mInputClosed; PRPackedBool mOutputClosed; - nsCOMPtr mDNSRequest; + nsCOMPtr mDNSRequest; + nsCOMPtr mDNSRecord; + PRNetAddr mNetAddr; // socket methods (these can only be called on the socket thread): @@ -296,14 +279,6 @@ private: else gSocketTransportService->PostEvent(this, MSG_OUTPUT_PENDING, 0, nsnull); } - - //------------------------------------------------------------------------- - // we have to be careful with these. they are modified on the DNS thread, - // while we are in the resolving state. once we've received the event - // MSG_DNS_LOOKUP_COMPLETE, these can only be accessed on the socket thread. - // - NetAddrList mNetAddrList; - PRNetAddr *mNetAddr; }; #endif // !nsSocketTransport_h__ diff --git a/mozilla/netwerk/base/src/nsSocketTransportService2.cpp b/mozilla/netwerk/base/src/nsSocketTransportService2.cpp index 08aa39afa51..5c3cdcca5f9 100644 --- a/mozilla/netwerk/base/src/nsSocketTransportService2.cpp +++ b/mozilla/netwerk/base/src/nsSocketTransportService2.cpp @@ -41,10 +41,10 @@ #include "nsSocketTransportService2.h" #include "nsSocketTransport2.h" -#include "nsPrintfCString.h" #include "nsReadableUtils.h" #include "nsAutoLock.h" #include "nsNetError.h" +#include "prnetdb.h" #include "prlock.h" #include "prerror.h" #include "plstr.h" @@ -354,70 +354,6 @@ nsSocketTransportService::ServiceEventQ() return keepGoing; } -//----------------------------------------------------------------------------- -// host:port -> ipaddr cache - -PLDHashTableOps nsSocketTransportService::ops = -{ - PL_DHashAllocTable, - PL_DHashFreeTable, - PL_DHashGetKeyStub, - PL_DHashStringKey, - PL_DHashMatchStringKey, - PL_DHashMoveEntryStub, - PL_DHashFreeStringKey, - PL_DHashFinalizeStub, - nsnull -}; - -nsresult -nsSocketTransportService::LookupHost(const nsACString &host, PRUint16 port, PRIPv6Addr *addr) -{ - NS_ASSERTION(!host.IsEmpty(), "empty host"); - NS_ASSERTION(addr, "null addr"); - - PLDHashEntryHdr *hdr; - nsCAutoString hostport(host + nsPrintfCString(":%d", port)); - - hdr = PL_DHashTableOperate(&mHostDB, hostport.get(), PL_DHASH_LOOKUP); - if (PL_DHASH_ENTRY_IS_BUSY(hdr)) { - // found match - nsHostEntry *ent = NS_REINTERPRET_CAST(nsHostEntry *, hdr); - memcpy(addr, &ent->addr, sizeof(ent->addr)); - return NS_OK; - } - - return NS_ERROR_UNKNOWN_HOST; -} - -nsresult -nsSocketTransportService::RememberHost(const nsACString &host, PRUint16 port, PRIPv6Addr *addr) -{ - // remember hostname - - PLDHashEntryHdr *hdr; - nsCAutoString hostport(host + nsPrintfCString(":%d", port)); - - hdr = PL_DHashTableOperate(&mHostDB, hostport.get(), PL_DHASH_ADD); - if (!hdr) - return NS_ERROR_FAILURE; - - NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr), "entry not busy"); - - nsHostEntry *ent = NS_REINTERPRET_CAST(nsHostEntry *, hdr); - if (ent->key == nsnull) { - ent->key = (const void *) ToNewCString(hostport); - memcpy(&ent->addr, addr, sizeof(ent->addr)); - } -#ifdef DEBUG - else { - // verify that the existing entry is in fact a perfect match - NS_ASSERTION(PL_strcmp(ent->hostport(), hostport.get()) == 0, "bad match"); - NS_ASSERTION(memcmp(&ent->addr, addr, sizeof(ent->addr)) == 0, "bad match"); - } -#endif - return NS_OK; -} //----------------------------------------------------------------------------- // xpcom api @@ -534,11 +470,6 @@ nsSocketTransportService::Run() gSocketThread = PR_GetCurrentThread(); - // - // Initialize hostname database - // - PL_DHashTableInit(&mHostDB, &ops, nsnull, sizeof(nsHostEntry), 0); - // // add thread event to poll list (mThreadEvent may be NULL) // @@ -650,9 +581,6 @@ nsSocketTransportService::Run() for (i=mIdleCount-1; i>=0; --i) DetachSocket(&mIdleList[i]); - // clear the hostname database - PL_DHashTableFinish(&mHostDB); - gSocketThread = nsnull; return NS_OK; } diff --git a/mozilla/netwerk/base/src/nsSocketTransportService2.h b/mozilla/netwerk/base/src/nsSocketTransportService2.h index 3a1f767ec64..f0c686ef05e 100644 --- a/mozilla/netwerk/base/src/nsSocketTransportService2.h +++ b/mozilla/netwerk/base/src/nsSocketTransportService2.h @@ -144,20 +144,6 @@ public: // nsresult AttachSocket(PRFileDesc *fd, nsASocketHandler *); - // - // LookupHost checks to see if we've previously resolved the hostname - // during this session. We remember all successful connections to prevent - // ip-address spoofing. See bug 149943. - // - // Returns TRUE if found, and sets |addr| to the cached value. - // - nsresult LookupHost(const nsACString &host, PRUint16 port, PRIPv6Addr *addr); - - // - // Remember host:port -> IP address mapping. - // - nsresult RememberHost(const nsACString &host, PRUint16 port, PRIPv6Addr *addr); - private: virtual ~nsSocketTransportService(); @@ -261,23 +247,6 @@ private: }; PendingSocket *mPendingQHead; PendingSocket *mPendingQTail; - - //------------------------------------------------------------------------- - // mHostDB maps host:port -> nsHostEntry - //------------------------------------------------------------------------- - - struct nsHostEntry : PLDHashEntryStub - { - PRIPv6Addr addr; - const char *hostport() const { return (const char *) key; } - }; - - static PLDHashTableOps ops; - - static PRBool PR_CALLBACK MatchEntry(PLDHashTable *, const PLDHashEntryHdr *, const void *); - static void PR_CALLBACK ClearEntry(PLDHashTable *, PLDHashEntryHdr *); - - PLDHashTable mHostDB; }; extern nsSocketTransportService *gSocketTransportService; diff --git a/mozilla/netwerk/build/nsNetCID.h b/mozilla/netwerk/build/nsNetCID.h index 600eb92638c..24d52f97da9 100644 --- a/mozilla/netwerk/build/nsNetCID.h +++ b/mozilla/netwerk/build/nsNetCID.h @@ -557,6 +557,18 @@ * netwerk/dns/ classes */ +#define NS_DNSSERVICE_CLASSNAME \ + "nsDNSService" +#define NS_DNSSERVICE_CONTRACTID \ + "@mozilla.org/network/dns-service;1" +#define NS_DNSSERVICE_CID \ +{ /* b0ff4572-dae4-4bef-a092-83c1b88f6be9 */ \ + 0xb0ff4572, \ + 0xdae4, \ + 0x4bef, \ + {0xa0, 0x92, 0x83, 0xc1, 0xb8, 0x8f, 0x6b, 0xe9} \ +} + #define NS_IDNSERVICE_CLASSNAME \ "nsIDNService" /* ContractID of the XPCOM package that implements nsIIDNService */ @@ -586,4 +598,37 @@ #define NS_MIMEHEADERPARAM_CONTRACTID "@mozilla.org/network/mime-hdrparam;1" + +/****************************************************************************** + * netwerk/socket classes + */ + +#define NS_SOCKETPROVIDERSERVICE_CLASSNAME \ + "nsSocketProviderService" +#define NS_SOCKETPROVIDERSERVICE_CONTRACTID \ + "@mozilla.org/network/socket-provider-service;1" +#define NS_SOCKETPROVIDERSERVICE_CID \ +{ /* ed394ba0-5472-11d3-bbc8-0000861d1237 */ \ + 0xed394ba0, \ + 0x5472, \ + 0x11d3, \ + { 0xbb, 0xc8, 0x00, 0x00, 0x86, 0x1d, 0x12, 0x37 } \ +} + +#define NS_SOCKSSOCKETPROVIDER_CID \ +{ /* 8dbe7246-1dd2-11b2-9b8f-b9a849e4403a */ \ + 0x8dbe7246, \ + 0x1dd2, \ + 0x11b2, \ + { 0x9b, 0x8f, 0xb9, 0xa8, 0x49, 0xe4, 0x40, 0x3a } \ +} + +#define NS_SOCKS4SOCKETPROVIDER_CID \ +{ /* F7C9F5F4-4451-41c3-A28A-5BA2447FBACE */ \ + 0xf7c9f5f4, \ + 0x4451, \ + 0x41c3, \ + { 0xa2, 0x8a, 0x5b, 0xa2, 0x44, 0x7f, 0xba, 0xce } \ +} + #endif // nsNetCID_h__ diff --git a/mozilla/netwerk/build/nsNetModule.cpp b/mozilla/netwerk/build/nsNetModule.cpp index 44f6c2296b5..c118d414241 100644 --- a/mozilla/netwerk/build/nsNetModule.cpp +++ b/mozilla/netwerk/build/nsNetModule.cpp @@ -47,7 +47,6 @@ #include "nsSocketProviderService.h" #include "nscore.h" #include "nsSimpleURI.h" -#include "nsDnsService.h" #include "nsLoadGroup.h" #include "nsStreamLoader.h" #include "nsUnicharStreamLoader.h" @@ -56,7 +55,6 @@ #include "nsBufferedStreams.h" #include "nsMIMEInputStream.h" #include "nsSOCKSSocketProvider.h" -#include "nsSOCKS4SocketProvider.h" #include "nsCacheService.h" #include "nsNetCID.h" @@ -73,6 +71,9 @@ #include "nsIOService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsIOService, Init) + +#include "nsDNSService2.h" +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDNSService, Init) #include "nsProtocolProxyService.h" NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsProtocolProxyService, Init) @@ -575,14 +576,14 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { NS_SOCKETTRANSPORTSERVICE_CID, NS_SOCKETTRANSPORTSERVICE_CONTRACTID, nsSocketTransportServiceConstructor }, - { "Socket Provider Service", + { NS_SOCKETPROVIDERSERVICE_CLASSNAME, NS_SOCKETPROVIDERSERVICE_CID, - "@mozilla.org/network/socket-provider-service;1", + NS_SOCKETPROVIDERSERVICE_CONTRACTID, nsSocketProviderService::Create }, - { "DNS Service", + { NS_DNSSERVICE_CLASSNAME, NS_DNSSERVICE_CID, - "@mozilla.org/network/dns-service;1", - nsDNSService::Create }, + NS_DNSSERVICE_CONTRACTID, + nsDNSServiceConstructor }, { NS_IDNSERVICE_CLASSNAME, NS_IDNSERVICE_CID, NS_IDNSERVICE_CONTRACTID, @@ -968,16 +969,16 @@ static const nsModuleComponentInfo gNetModuleInfo[] = { }, #endif - { NS_ISOCKSSOCKETPROVIDER_CLASSNAME, + { "nsSOCKSSocketProvider", NS_SOCKSSOCKETPROVIDER_CID, - NS_ISOCKSSOCKETPROVIDER_CONTRACTID, - nsSOCKSSocketProvider::Create + NS_NETWORK_SOCKET_CONTRACTID_PREFIX "socks", + nsSOCKSSocketProvider::CreateV5 }, - { NS_ISOCKS4SOCKETPROVIDER_CLASSNAME, + { "nsSOCKS4SocketProvider", NS_SOCKS4SOCKETPROVIDER_CID, - NS_ISOCKS4SOCKETPROVIDER_CONTRACTID, - nsSOCKS4SocketProvider::Create + NS_NETWORK_SOCKET_CONTRACTID_PREFIX "socks4", + nsSOCKSSocketProvider::CreateV4 }, { NS_CACHESERVICE_CLASSNAME, diff --git a/mozilla/netwerk/dns/public/Makefile.in b/mozilla/netwerk/dns/public/Makefile.in index dba8e7f4cf0..4a36e2a4294 100644 --- a/mozilla/netwerk/dns/public/Makefile.in +++ b/mozilla/netwerk/dns/public/Makefile.in @@ -1,3 +1,4 @@ +# vim: noexpandtab ts=8 sw=8 # # The contents of this file are subject to the Netscape Public # License Version 1.1 (the "License"); you may not use this file @@ -31,10 +32,11 @@ XPIDL_MODULE = necko_dns GRE_MODULE = 1 XPIDLSRCS = \ - nsIDNSListener.idl \ nsIDNSService.idl \ + nsIDNSListener.idl \ + nsIDNSRequest.idl \ + nsIDNSRecord.idl \ nsIIDNService.idl \ $(NULL) include $(topsrcdir)/config/rules.mk - diff --git a/mozilla/netwerk/dns/public/nsIDNSListener.idl b/mozilla/netwerk/dns/public/nsIDNSListener.idl index 416996e2004..a150e425c35 100644 --- a/mozilla/netwerk/dns/public/nsIDNSListener.idl +++ b/mozilla/netwerk/dns/public/nsIDNSListener.idl @@ -1,73 +1,62 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * - * The Original Code is mozilla.org code. + * The Original Code is Mozilla. * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. * * Contributor(s): + * IBM Corp. * * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or + * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your + * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. + * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsISupports.idl" -%{C++ -#include "prnetdb.h" +interface nsIDNSRequest; +interface nsIDNSRecord; -typedef struct nsHostEnt -{ - PRHostEnt hostEnt; - char buffer[PR_NETDB_BUF_SIZE]; - PRIntn bufLen; - char * bufPtr; -} nsHostEnt; -%} - -[ptr] native nsHostEntStar(nsHostEnt); - -[scriptable, uuid(7686cef0-206e-11d3-9348-00104ba0fd40)] +/** + * nsIDNSListener + */ +[scriptable, uuid(36413eba-3a2a-444d-b88e-df9b6d306b73)] interface nsIDNSListener : nsISupports { /** - * Notify the listener that we are about to lookup the requested hostname. + * called when an asynchronous host lookup completes. + * + * @param aRequest + * the value returned from asyncResolve. + * @param aRecord + * the DNS record corresponding to the hostname that was resolved. + * this parameter is null if there was an error. + * @param aStatus + * if the lookup failed, this parameter gives the reason. */ - void OnStartLookup(in nsISupports ctxt, in string hostname); - - /** - * Notify the listener that we have found one or more addresses for the hostname. - */ - [noscript] void OnFound(in nsISupports ctxt, in string hostname, - in nsHostEntStar entry); - - /** - * Notify the listener that the lookup has completed. - */ - void OnStopLookup(in nsISupports ctxt, in string hostname, in nsresult status); + void onLookupComplete(in nsIDNSRequest aRequest, + in nsIDNSRecord aRecord, + in nsresult aStatus); }; - diff --git a/mozilla/netwerk/dns/public/nsIDNSRecord.idl b/mozilla/netwerk/dns/public/nsIDNSRecord.idl new file mode 100644 index 00000000000..9c2b10de936 --- /dev/null +++ b/mozilla/netwerk/dns/public/nsIDNSRecord.idl @@ -0,0 +1,87 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +[ptr] native PRNetAddrStar(union PRNetAddr); + +/** + * nsIDNSRecord + * + * this interface represents the result of a DNS lookup. since a DNS + * query may return more than one resolved IP address, the record acts + * like an enumerator, allowing the caller to easily step through the + * list of IP addresses. + */ +[scriptable, uuid(31c9c52e-1100-457d-abac-d2729e43f506)] +interface nsIDNSRecord : nsISupports +{ + /** + * @return the canonical hostname for this record. + * + * e.g., www.mozilla.org --> gila.mozilla.org + */ + readonly attribute ACString canonicalName; + + /** + * this function copies the value of the next IP address into the + * given PRNetAddr struct and increments the internal address iterator. + * + * @throws NS_ERROR_NOT_AVAILABLE if there is not another IP address in + * the record. + */ + [noscript] void getNextAddr(in PRUint16 port, in PRNetAddrStar addr); + + /** + * this function returns the value of the next IP address as a + * string and increments the internal address iterator. + * + * @throws NS_ERROR_NOT_AVAILABLE if there is not another IP address in + * the record. + */ + ACString getNextAddrAsString(); + + /** + * this function returns true if there is another address in the record. + */ + boolean hasMore(); + + /** + * this function resets the internal address iterator to the first + * address in the record. + */ + void rewind(); +}; diff --git a/mozilla/netwerk/dns/public/nsIDNSRequest.idl b/mozilla/netwerk/dns/public/nsIDNSRequest.idl new file mode 100644 index 00000000000..78b1a511583 --- /dev/null +++ b/mozilla/netwerk/dns/public/nsIDNSRequest.idl @@ -0,0 +1,51 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +/** + * nsIDNSRequest + */ +[scriptable, uuid(3e538aea-d84b-4bf4-bae1-55f9969fe50e)] +interface nsIDNSRequest : nsISupports +{ + /** + * called to cancel a pending asynchronous DNS request. the listener will + * passed to asyncResolve will be notified immediately with a status code + * of NS_ERROR_ABORT. + */ + void cancel(); +}; diff --git a/mozilla/netwerk/dns/public/nsIDNSService.idl b/mozilla/netwerk/dns/public/nsIDNSService.idl index 049fe5ea1a9..49ac10184a7 100644 --- a/mozilla/netwerk/dns/public/nsIDNSService.idl +++ b/mozilla/netwerk/dns/public/nsIDNSService.idl @@ -1,83 +1,106 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * - * The Original Code is mozilla.org code. + * The Original Code is Mozilla. * - * The Initial Developer of the Original Code is + * The Initial Developer of the Original Code is * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 + * Portions created by the Initial Developer are Copyright (C) 2003 * the Initial Developer. All Rights Reserved. * * Contributor(s): + * Gordon Sheridan + * IBM Corp. * * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or + * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your + * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. + * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -#include "nsISupports.idl" +#include "nsIDNSRecord.idl" +#include "nsIDNSRequest.idl" +#include "nsIDNSListener.idl" -%{C++ -#include "nsNetError.h" +interface nsIEventQueue; -#define NS_DNSSERVICE_CID \ -{ /* 718e7c81-f8b8-11d2-b951-c80918051d3c */ \ - 0x718e7c81, \ - 0xf8b8, \ - 0x11d2, \ - { 0xb9, 0x51, 0xc8, 0x09, 0x18, 0x05, 0x1d, 0x3c } \ -} - -%} - -interface nsIRequest; -interface nsIDNSListener; - -[scriptable, uuid(598f2f80-206f-11d3-9348-00104ba0fd40)] +/** + * nsIDNSService + */ +[scriptable, uuid(98519315-f139-405e-9182-3339907c29fd)] interface nsIDNSService : nsISupports { - nsIRequest lookup(in string hostname, - in nsIDNSListener listener, - in nsISupports ctxt); - /** - * Synchronously resolve the hostname to its IP address. - */ - string resolve(in string hostname); - - /** - * returns our own IP address - */ - readonly attribute string myIPAddress; - - /** - * Check if the specified address is in the network of the pattern - * using the specified mask. This function would probably go away - * once an implementation for it in JS exists for nsProxyAutoConfig. - * See http://www.mozilla.org/docs/netlib/pac.html for more info. - */ - boolean isInNet(in string ipaddr, in string pattern, in string mask); - + * called to initialize the DNS service. + */ void init(); + + /** + * called to shutdown the DNS service. any pending asynchronous + * requests will be canceled, and the local cache of DNS records + * will be cleared. NOTE: the operating system may still have + * its own cache of DNS records, which would be unaffected by + * this method. + */ void shutdown(); + + /** + * kicks off an asynchronous host lookup. + * + * @param aHostName + * the hostname or IP-address-literal to resolve. + * @param aBypassCache + * if true, the internal DNS lookup cache will be bypassed. + * @param aListener + * the listener to be notified when the result is available. + * @param aListenerEventQ + * optional parameter (may be null). if non-null, this parameter + * specifies the nsIEventQueue of the thread on which the listener's + * onLookupComplete should be called. however, if this parameter is + * null, then onLookupComplete will be called on an unspecified + * thread (possibly recursively). + * + * @return DNS request instance that can be used to cancel the host lookup. + */ + nsIDNSRequest asyncResolve(in AUTF8String aHostName, + in boolean aBypassCache, + in nsIDNSListener aListener, + in nsIEventQueue aListenerEventQ); + + /** + * called to synchronously resolve a hostname. + * + * @param aHostName + * the hostname or IP-address-literal to resolve. + * @param aBypassCache + * if true, the internal DNS lookup cache will be bypassed. + * + * @return DNS record corresponding to the given hostname. + * @throws NS_ERROR_UNKNOWN_HOST if host could not be resolved. + */ + nsIDNSRecord resolve(in AUTF8String aHostName, + in boolean aBypassCache); + + /** + * @return the hostname of the operating system. + */ + readonly attribute AUTF8String myHostName; }; diff --git a/mozilla/netwerk/dns/src/Makefile.in b/mozilla/netwerk/dns/src/Makefile.in index 20809edfc98..891cd61361b 100644 --- a/mozilla/netwerk/dns/src/Makefile.in +++ b/mozilla/netwerk/dns/src/Makefile.in @@ -1,3 +1,4 @@ +# vim: noexpandtab ts=8 sw=8 # # The contents of this file are subject to the Netscape Public # License Version 1.1 (the "License"); you may not use this file @@ -34,16 +35,18 @@ REQUIRES = xpcom \ unicharutil \ $(NULL) -CPPSRCS = nsDnsService.cpp \ - nsIDNService.cpp +CPPSRCS = nsIDNService.cpp \ + nsDNSService2.cpp \ + nsHostResolver.cpp \ + $(NULL) -CSRCS = race.c \ - nameprep.c \ - punycode.c +CSRCS = race.c \ + nameprep.c \ + punycode.c \ + $(NULL) # we don't want the shared lib, but we want to force the creation of a # static lib. FORCE_STATIC_LIB = 1 include $(topsrcdir)/config/rules.mk - diff --git a/mozilla/netwerk/dns/src/nsDNSService2.cpp b/mozilla/netwerk/dns/src/nsDNSService2.cpp new file mode 100644 index 00000000000..c241b9ee480 --- /dev/null +++ b/mozilla/netwerk/dns/src/nsDNSService2.cpp @@ -0,0 +1,456 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsDNSService2.h" +#include "nsIProxyObjectManager.h" +#include "nsIPrefService.h" +#include "nsIPrefBranch.h" +#include "nsIPrefBranchInternal.h" +#include "nsIServiceManager.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nsAutoLock.h" +#include "nsAutoPtr.h" +#include "nsNetCID.h" +#include "nsNetError.h" +#include "prsystem.h" +#include "prnetdb.h" +#include "prmon.h" +#include "prio.h" + +static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries"; +static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration"; +static const char kPrefEnableIDN[] = "network.enableIDN"; + +//----------------------------------------------------------------------------- + +class nsDNSRecord : public nsIDNSRecord +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSRECORD + + nsDNSRecord(nsAddrInfo *ai) + : mAddrInfo(ai) + , mIter(nsnull) + , mDone(PR_FALSE) {} + +private: + virtual ~nsDNSRecord() {} + + nsRefPtr mAddrInfo; + void *mIter; + PRBool mDone; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsDNSRecord, nsIDNSRecord) + +NS_IMETHODIMP +nsDNSRecord::GetCanonicalName(nsACString &result) +{ + NS_ENSURE_TRUE(mAddrInfo, NS_ERROR_NOT_AVAILABLE); + result.Assign(PR_GetCanonNameFromAddrInfo(mAddrInfo->get())); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::GetNextAddr(PRUint16 port, PRNetAddr *addr) +{ + NS_ENSURE_TRUE(mAddrInfo, NS_ERROR_NOT_AVAILABLE); + + // not a programming error to poke the DNS record when it has + // no more entries. just silently fail. this enables consumers + // to enumerate the DNS record without calling HasMore. + if (mDone) + return NS_ERROR_NOT_AVAILABLE; + + mIter = PR_EnumerateAddrInfo(mIter, mAddrInfo->get(), port, addr); + mDone = !mIter; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::GetNextAddrAsString(nsACString &result) +{ + PRNetAddr addr; + nsresult rv = GetNextAddr(0, &addr); + if (NS_FAILED(rv)) return rv; + + char buf[64]; + if (PR_NetAddrToString(&addr, buf, sizeof(buf)) == PR_SUCCESS) { + result.Assign(buf); + return NS_OK; + } + NS_ERROR("PR_NetAddrToString failed unexpectedly"); + return NS_ERROR_FAILURE; // conversion failed for some reason +} + +NS_IMETHODIMP +nsDNSRecord::HasMore(PRBool *result) +{ + *result = !mDone; + return NS_OK; +} + +NS_IMETHODIMP +nsDNSRecord::Rewind() +{ + mIter = nsnull; + mDone = PR_FALSE; + return NS_OK; +} + +//----------------------------------------------------------------------------- + +class nsDNSAsyncRequest : public nsResolveHostCB + , public nsIDNSRequest +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSREQUEST + + nsDNSAsyncRequest(nsHostResolver *res, + const nsACString &host, + nsIDNSListener *listener) + : mResolver(res) + , mHost(host) + , mListener(listener) {} + virtual ~nsDNSAsyncRequest() {} + + void OnLookupComplete(nsHostResolver *, const char *, nsresult, nsAddrInfo *); + + nsRefPtr mResolver; + nsCString mHost; // hostname we're resolving + nsCOMPtr mListener; +}; + +void +nsDNSAsyncRequest::OnLookupComplete(nsHostResolver *resolver, + const char *host, + nsresult status, + nsAddrInfo *ai) +{ + nsDNSRecord *rec; + if (!ai) + rec = nsnull; + else { + rec = new nsDNSRecord(ai); + if (!rec) + status = NS_ERROR_OUT_OF_MEMORY; + } + + mListener->OnLookupComplete(this, rec, status); + mListener = nsnull; + + // release the reference to ourselves that was added before we were + // handed off to the host resolver. + NS_RELEASE_THIS(); +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsDNSAsyncRequest, nsIDNSRequest) + +NS_IMETHODIMP +nsDNSAsyncRequest::Cancel() +{ + mResolver->DetachCallback(mHost.get(), this); + return NS_OK; +} + +//----------------------------------------------------------------------------- + +class nsDNSSyncRequest : public nsResolveHostCB +{ +public: + nsDNSSyncRequest(PRMonitor *mon) + : mDone(PR_FALSE) + , mStatus(NS_OK) + , mMonitor(mon) {} + virtual ~nsDNSSyncRequest() {} + + void OnLookupComplete(nsHostResolver *, const char *, nsresult, nsAddrInfo *); + + PRBool mDone; + nsresult mStatus; + nsRefPtr mAddrInfo; + +private: + PRMonitor *mMonitor; +}; + +void +nsDNSSyncRequest::OnLookupComplete(nsHostResolver *resolver, + const char *host, + nsresult status, + nsAddrInfo *ai) +{ + // store results, and wake up nsDNSService::Resolve to process results. + PR_EnterMonitor(mMonitor); + mDone = PR_TRUE; + mStatus = status; + mAddrInfo = ai; + PR_Notify(mMonitor); + PR_ExitMonitor(mMonitor); +} + +//----------------------------------------------------------------------------- + +nsDNSService::nsDNSService() + : mLock(nsnull) +{ +} + +nsDNSService::~nsDNSService() +{ + if (mLock) + PR_DestroyLock(mLock); +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsDNSService, nsIDNSService, nsIObserver) + +NS_IMETHODIMP +nsDNSService::Init() +{ + NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED); + + PRBool firstTime = (mLock == nsnull); + + // prefs + PRUint32 maxCacheEntries = 20; + PRUint32 maxCacheLifetime = 5; // minutes + PRBool enableIDN = PR_TRUE; + + // read prefs + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + PRInt32 val; + if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheEntries, &val))) + maxCacheEntries = val; + if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheExpiration, &val))) + maxCacheLifetime = (val / 60); // convert from seconds to minutes + if (NS_SUCCEEDED(prefs->GetBoolPref(kPrefEnableIDN, (PRBool*)&val))) + enableIDN = (PRBool) val; + } + + // we have to null out mIDN since we might be getting re-initialized + // as a result of a pref change. + if (enableIDN) + mIDN = do_GetService(NS_IDNSERVICE_CONTRACTID); + else + mIDN = nsnull; + + if (firstTime) { + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + // register as prefs observer + nsCOMPtr prefsInt = do_QueryInterface(prefs); + if (prefsInt) { + prefsInt->AddObserver(kPrefDnsCacheEntries, this, PR_FALSE); + prefsInt->AddObserver(kPrefDnsCacheExpiration, this, PR_FALSE); + prefsInt->AddObserver(kPrefEnableIDN, this, PR_FALSE); + } + } + + return nsHostResolver::Create(maxCacheEntries, + maxCacheLifetime, + getter_AddRefs(mResolver)); +} + +NS_IMETHODIMP +nsDNSService::Shutdown() +{ + nsRefPtr res; + { + nsAutoLock lock(mLock); + res = mResolver; + mResolver = nsnull; + } + if (res) + res->Shutdown(); + return NS_OK; +} + +NS_IMETHODIMP +nsDNSService::AsyncResolve(const nsACString &hostname, + PRBool bypassCache, + nsIDNSListener *listener, + nsIEventQueue *eventQ, + nsIDNSRequest **result) +{ + // grab reference to global host resolver and IDN service. beware + // simultaneous shutdown!! + nsRefPtr res; + nsCOMPtr idn; + { + nsAutoLock lock(mLock); + res = mResolver; + idn = mIDN; + } + NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE); + + const nsACString *hostPtr = &hostname; + + nsresult rv; + nsCAutoString hostBuf; + if (idn && !IsASCII(hostname)) { + rv = idn->ConvertUTF8toACE(hostname, hostBuf); + if (NS_SUCCEEDED(rv)) + hostPtr = &hostBuf; + } + + nsCOMPtr listenerProxy; + if (eventQ) { + rv = NS_GetProxyForObject(eventQ, + NS_GET_IID(nsIDNSListener), + listener, + PROXY_ASYNC | PROXY_ALWAYS, + getter_AddRefs(listenerProxy)); + if (NS_FAILED(rv)) return rv; + listener = listenerProxy; + } + + nsDNSAsyncRequest *req = new nsDNSAsyncRequest(res, *hostPtr, listener); + if (!req) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*result = req); + + // addref for resolver; will be released when OnLookupComplete is called. + NS_ADDREF(req); + rv = res->ResolveHost(req->mHost.get(), bypassCache, req); + if (NS_FAILED(rv)) { + NS_RELEASE(req); + NS_RELEASE(*result); + } + return rv; +} + +NS_IMETHODIMP +nsDNSService::Resolve(const nsACString &hostname, + PRBool bypassCache, + nsIDNSRecord **result) +{ + // grab reference to global host resolver and IDN service. beware + // simultaneous shutdown!! + nsRefPtr res; + nsCOMPtr idn; + { + nsAutoLock lock(mLock); + res = mResolver; + idn = mIDN; + } + NS_ENSURE_TRUE(res, NS_ERROR_OFFLINE); + + const nsACString *hostPtr = &hostname; + + nsresult rv; + nsCAutoString hostBuf; + if (idn && !IsASCII(hostname)) { + rv = idn->ConvertUTF8toACE(hostname, hostBuf); + if (NS_SUCCEEDED(rv)) + hostPtr = &hostBuf; + } + + // + // sync resolve: since the host resolver only works asynchronously, we need + // to use a mutex and a condvar to wait for the result. however, since the + // result may be in the resolvers cache, we might get called back recursively + // on the same thread. so, our mutex needs to be re-entrant. inotherwords, + // we need to use a monitor! ;-) + // + + PRMonitor *mon = PR_NewMonitor(); + if (!mon) + return NS_ERROR_OUT_OF_MEMORY; + + PR_EnterMonitor(mon); + nsDNSSyncRequest syncReq(mon); + + rv = res->ResolveHost(PromiseFlatCString(*hostPtr).get(), bypassCache, &syncReq); + if (NS_SUCCEEDED(rv)) { + // wait for result + while (!syncReq.mDone) + PR_Wait(mon, PR_INTERVAL_NO_TIMEOUT); + + if (NS_FAILED(syncReq.mStatus)) + rv = syncReq.mStatus; + else { + nsDNSRecord *rec = new nsDNSRecord(syncReq.mAddrInfo); + if (!rec) + rv = NS_ERROR_OUT_OF_MEMORY; + else + NS_ADDREF(*result = rec); + } + } + + PR_ExitMonitor(mon); + PR_DestroyMonitor(mon); + return rv; +} + +NS_IMETHODIMP +nsDNSService::GetMyHostName(nsACString &result) +{ + char name[100]; + if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) { + result = name; + return NS_OK; + } + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsDNSService::Observe(nsISupports *subject, const char *topic, const PRUnichar *data) +{ + // we are only getting called if a preference has changed. + NS_ASSERTION(strcmp(topic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, + "unexpected observe call"); + + // + // Shutdown and this function are both only called on the UI thread, so we don't + // have to worry about mResolver being cleared out from under us. + // + // NOTE Shutting down and reinitializing the service like this is obviously + // suboptimal if Observe gets called several times in a row, but we don't + // expect that to be the case. + // + + if (mResolver) { + Shutdown(); + Init(); + } + return NS_OK; +} diff --git a/mozilla/netwerk/dns/src/nsDNSService2.h b/mozilla/netwerk/dns/src/nsDNSService2.h new file mode 100644 index 00000000000..b442a74b7e6 --- /dev/null +++ b/mozilla/netwerk/dns/src/nsDNSService2.h @@ -0,0 +1,61 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDNSService.h" +#include "nsIIDNService.h" +#include "nsIObserver.h" +#include "nsHostResolver.h" +#include "nsAutoPtr.h" +#include "prlock.h" + +class nsDNSService : public nsIDNSService + , public nsIObserver +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDNSSERVICE + NS_DECL_NSIOBSERVER + + nsDNSService(); + virtual ~nsDNSService(); + +private: + nsRefPtr mResolver; + nsCOMPtr mIDN; + PRLock *mLock; + + // mLock protects access to mResolver +}; diff --git a/mozilla/netwerk/dns/src/nsHostResolver.cpp b/mozilla/netwerk/dns/src/nsHostResolver.cpp new file mode 100644 index 00000000000..724c9039910 --- /dev/null +++ b/mozilla/netwerk/dns/src/nsHostResolver.cpp @@ -0,0 +1,602 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#if defined(HAVE_RES_NINIT) +#include +#include +#include +#include +#include +#define RES_RETRY_ON_FAILURE +#endif + +#include +#include "nsHostResolver.h" +#include "nsNetError.h" +#include "nsISupportsBase.h" +#include "nsISupportsUtils.h" +#include "nsAutoLock.h" +#include "nsAutoPtr.h" +#include "pratom.h" +#include "prthread.h" +#include "prerror.h" +#include "prcvar.h" +#include "prtime.h" +#include "prlong.h" +#include "pldhash.h" +#include "plstr.h" + +//---------------------------------------------------------------------------- + +#define MAX_THREADS 8 +#define THREAD_IDLE_TIMEOUT PR_SecondsToInterval(5) + +//---------------------------------------------------------------------------- + +//#define DEBUG_HOST_RESOLVER +#ifdef DEBUG_HOST_RESOLVER +#define LOG(args) printf args +#else +#define LOG(args) +#endif + +//---------------------------------------------------------------------------- + +static inline void +MoveCList(PRCList &from, PRCList &to) +{ + if (!PR_CLIST_IS_EMPTY(&from)) { + to.next = from.next; + to.prev = from.prev; + to.next->prev = &to; + to.prev->next = &to; + PR_INIT_CLIST(&from); + } +} + +static PRUint32 +NowInMinutes() +{ + PRTime now = PR_Now(), minutes, factor; + LL_I2L(factor, 60 * PR_USEC_PER_SEC); + LL_DIV(minutes, now, factor); + PRUint32 result; + LL_L2UI(result, minutes); + return result; +} + +//---------------------------------------------------------------------------- + +#if defined(RES_RETRY_ON_FAILURE) + +// this class represents the resolver state for a given thread. if we +// encounter a lookup failure, then we can invoke the Reset method on an +// instance of this class to reset the resolver (in case /etc/resolv.conf +// for example changed). this is mainly an issue on GNU systems since glibc +// only reads in /etc/resolv.conf once per thread. it may be an issue on +// other systems as well. + +class nsResState +{ +public: + nsResState() + // initialize mLastReset to the time when this object + // is created. this means that a reset will not occur + // if a thread is too young. the alternative would be + // to initialize this to the beginning of time, so that + // the first failure would cause a reset, but since the + // thread would have just started up, it likely would + // already have current /etc/resolv.conf info. + : mLastReset(PR_IntervalNow()) + { + } + + PRBool Reset() + { + // reset no more than once per second + if (PR_IntervalToSeconds(PR_IntervalNow() - mLastReset) < 1) + return PR_FALSE; + + LOG(("calling res_ninit\n")); + + mLastReset = PR_IntervalNow(); + return (res_ninit(&_res) == 0); + } + +private: + PRIntervalTime mLastReset; +}; + +#endif // RES_RETRY_ON_FAILURE + +//---------------------------------------------------------------------------- + +class nsHostRecord : public PRCList +{ +public: + NET_DECL_REFCOUNTED_THREADSAFE + + nsHostRecord(const char *h) + : host(PL_strdup(h)) + , expireTime(NowInMinutes()) + , mRefCount(0) + { + PR_INIT_CLIST(this); + PR_INIT_CLIST(&callbacks); + } + ~nsHostRecord() + { + PL_strfree(host); + } + + char *host; + nsRefPtr addr; + PRUint32 expireTime; // minutes since epoch + PRCList callbacks; + +private: + PRInt32 mRefCount; +}; + +//---------------------------------------------------------------------------- + +struct nsHostDBEnt : PLDHashEntryHdr +{ + nsHostRecord *rec; +}; + +static const void * PR_CALLBACK +HostDB_GetKey(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, entry); + return he->rec->host; +} + +static PRBool PR_CALLBACK +HostDB_MatchEntry(PLDHashTable *table, + const PLDHashEntryHdr *entry, + const void *key) +{ + const nsHostDBEnt *he = NS_STATIC_CAST(const nsHostDBEnt *, entry); + return !strcmp(he->rec->host, (const char *) key); +} + +static void PR_CALLBACK +HostDB_MoveEntry(PLDHashTable *table, + const PLDHashEntryHdr *from, + PLDHashEntryHdr *to) +{ + NS_STATIC_CAST(nsHostDBEnt *, to)->rec = + NS_STATIC_CAST(const nsHostDBEnt *, from)->rec; +} + +static void PR_CALLBACK +HostDB_ClearEntry(PLDHashTable *table, + PLDHashEntryHdr *entry) +{ + nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, entry); +#ifdef DEBUG_HOST_RESOLVER + if (!he->rec->addr) + LOG(("%s: => null\n", he->rec->host)); + else { + PRInt32 now = (PRInt32) NowInMinutes(); + PRInt32 diff = (PRInt32) he->rec->expireTime - now; + LOG(("%s: exp=%d => %s\n", + he->rec->host, diff, + PR_GetCanonNameFromAddrInfo(he->rec->addr->get()))); + void *iter = nsnull; + PRNetAddr addr; + char buf[64]; + do { + iter = PR_EnumerateAddrInfo(iter, he->rec->addr->get(), 0, &addr); + PR_NetAddrToString(&addr, buf, sizeof(buf)); + LOG((" %s\n", buf)); + } while (iter); + } +#endif + NS_RELEASE(he->rec); +} + +static PRBool PR_CALLBACK +HostDB_InitEntry(PLDHashTable *table, + PLDHashEntryHdr *entry, + const void *key) +{ + nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, entry); + he->rec = new nsHostRecord(NS_REINTERPRET_CAST(const char *, key)); + // addref result if initialized correctly; otherwise, leave record + // null so caller can detect and propagate error. + if (he->rec) { + if (he->rec->host) + NS_ADDREF(he->rec); + else { + delete he->rec; + he->rec = nsnull; + } + } + return PR_TRUE; +} + +static PLDHashTableOps gHostDB_ops = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + HostDB_GetKey, + PL_DHashStringKey, + HostDB_MatchEntry, + HostDB_MoveEntry, + HostDB_ClearEntry, + PL_DHashFinalizeStub, + HostDB_InitEntry, +}; + +static PLDHashOperator PR_CALLBACK +HostDB_RemoveEntry(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + return PL_DHASH_REMOVE; +} + +//---------------------------------------------------------------------------- + +nsHostResolver::nsHostResolver(PRUint32 maxCacheEntries, + PRUint32 maxCacheLifetime) + : mRefCount(0) + , mMaxCacheEntries(maxCacheEntries) + , mMaxCacheLifetime(maxCacheLifetime) + , mLock(nsnull) + , mIdleThreadCV(nsnull) + , mHaveIdleThread(PR_FALSE) + , mThreadCount(0) + , mEvictionQSize(0) + , mShutdown(PR_TRUE) +{ + mCreationTime = PR_Now(); + PR_INIT_CLIST(&mPendingQ); + PR_INIT_CLIST(&mEvictionQ); +} + +nsHostResolver::~nsHostResolver() +{ + if (mIdleThreadCV) + PR_DestroyCondVar(mIdleThreadCV); + + if (mLock) + PR_DestroyLock(mLock); + + PL_DHashTableFinish(&mDB); +} + +nsresult +nsHostResolver::Init() +{ + mLock = PR_NewLock(); + if (!mLock) + return NS_ERROR_OUT_OF_MEMORY; + + mIdleThreadCV = PR_NewCondVar(mLock); + if (!mIdleThreadCV) + return NS_ERROR_OUT_OF_MEMORY; + + PL_DHashTableInit(&mDB, &gHostDB_ops, nsnull, sizeof(nsHostDBEnt), 0); + + mShutdown = PR_FALSE; + return NS_OK; +} + +void +nsHostResolver::Shutdown() +{ + LOG(("nsHostResolver::Shutdown\n")); + + PRCList pendingQ; + PR_INIT_CLIST(&pendingQ); + { + nsAutoLock lock(mLock); + + mShutdown = PR_TRUE; + + MoveCList(mPendingQ, pendingQ); + + if (mHaveIdleThread) + PR_NotifyCondVar(mIdleThreadCV); + + // empty host database + PL_DHashTableEnumerate(&mDB, HostDB_RemoveEntry, nsnull); + } + + // loop through pending queue, erroring out pending lookups. + if (!PR_CLIST_IS_EMPTY(&pendingQ)) { + PRCList *node = pendingQ.next; + while (node != &pendingQ) { + nsHostRecord *rec = NS_STATIC_CAST(nsHostRecord *, node); + node = node->next; + OnLookupComplete(rec, NS_ERROR_ABORT, nsnull); + } + } +} + +nsresult +nsHostResolver::ResolveHost(const char *host, + PRBool bypassCache, + nsResolveHostCB *callback) +{ + NS_ENSURE_TRUE(host && *host, NS_ERROR_UNEXPECTED); + + nsAutoLock lock(mLock); + + if (mShutdown) + return NS_ERROR_NOT_INITIALIZED; + + // check to see if there is already an entry for this |host| + // in the hash table. if so, then check to see if we can't + // just reuse the lookup result. otherwise, if there are + // any pending callbacks, then add to pending callbacks queue, + // and return. otherwise, add ourselves as first pending + // callback, and proceed to do the lookup. + + PLDHashEntryHdr *hdr; + + hdr = PL_DHashTableOperate(&mDB, host, PL_DHASH_ADD); + if (!hdr) + return NS_ERROR_OUT_OF_MEMORY; + + nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, hdr); + if (!he->rec) + return NS_ERROR_OUT_OF_MEMORY; + else if (!bypassCache && + he->rec->addr && NowInMinutes() <= he->rec->expireTime) { + // ok, we can reuse this result. but, since we are + // making a callback, we must only do so outside the + // lock, and that requires holding an owning reference + // to the addrinfo structure. + nsRefPtr ai = he->rec->addr; + lock.unlock(); + callback->OnLookupComplete(this, host, NS_OK, ai); + lock.lock(); + return NS_OK; + } + + PRBool doLookup = PR_CLIST_IS_EMPTY(&he->rec->callbacks); + + // add callback to the list of pending callbacks + PR_APPEND_LINK(callback, &he->rec->callbacks); + + nsresult rv = NS_OK; + if (doLookup) { + rv = IssueLookup(he->rec); + if (NS_FAILED(rv)) + PR_REMOVE_AND_INIT_LINK(callback); + } + return rv; +} + +void +nsHostResolver::DetachCallback(const char *host, + nsResolveHostCB *callback) +{ + PRBool doCallback = PR_FALSE; + { + nsAutoLock lock(mLock); + + nsHostDBEnt *he = NS_STATIC_CAST(nsHostDBEnt *, + PL_DHashTableOperate(&mDB, host, PL_DHASH_LOOKUP)); + if (he && he->rec) { + // walk list looking for |callback|... we cannot assume + // that it will be there! + PRCList *node = he->rec->callbacks.next; + while (node != &he->rec->callbacks) { + if (NS_STATIC_CAST(nsResolveHostCB *, node) == callback) { + PR_REMOVE_LINK(callback); + doCallback = PR_TRUE; + break; + } + node = node->next; + } + } + } + + if (doCallback) + callback->OnLookupComplete(this, host, NS_ERROR_ABORT, nsnull); +} + +nsresult +nsHostResolver::IssueLookup(nsHostRecord *rec) +{ + // add rec to mPendingQ, possibly removing it from mEvictionQ. + // if rec is on mEvictionQ, then we can just move the owning + // reference over to mPendingQ. + if (rec->next == rec) + NS_ADDREF(rec); + else { + PR_REMOVE_LINK(rec); + mEvictionQSize--; + } + PR_APPEND_LINK(rec, &mPendingQ); + + if (mHaveIdleThread) { + // wake up idle thread to process this lookup + PR_NotifyCondVar(mIdleThreadCV); + } + else if (mThreadCount < MAX_THREADS) { + // dispatch new worker thread + NS_ADDREF_THIS(); // owning reference passed to thread + mThreadCount++; + PRThread *thr = PR_CreateThread(PR_SYSTEM_THREAD, + ThreadFunc, + this, + PR_PRIORITY_NORMAL, + PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, + 0); + if (!thr) { + mThreadCount--; + NS_RELEASE_THIS(); + return NS_ERROR_OUT_OF_MEMORY; + } + } + + return NS_OK; +} + +PRBool +nsHostResolver::GetHostToLookup(nsHostRecord **result) +{ + nsAutoLock lock(mLock); + + while (PR_CLIST_IS_EMPTY(&mPendingQ) && !mHaveIdleThread && !mShutdown) { + // become the idle thread and wait for a lookup + mHaveIdleThread = PR_TRUE; + PR_WaitCondVar(mIdleThreadCV, THREAD_IDLE_TIMEOUT); + mHaveIdleThread = PR_FALSE; + } + + if (!PR_CLIST_IS_EMPTY(&mPendingQ)) { + // remove next record from mPendingQ; hand over owning reference. + *result = NS_STATIC_CAST(nsHostRecord *, mPendingQ.next); + PR_REMOVE_AND_INIT_LINK(*result); + return PR_TRUE; + } + + // tell thread to exit... + mThreadCount--; + return PR_FALSE; +} + +void +nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, PRAddrInfo *result) +{ + nsAddrInfo *ai; + if (!result) + ai = nsnull; + else { + ai = new nsAddrInfo(result); + if (!ai) { + status = NS_ERROR_OUT_OF_MEMORY; + PR_FreeAddrInfo(result); + } + } + + // get the list of pending callbacks for this lookup, and notify + // them that the lookup is complete. + PRCList cbs; + PR_INIT_CLIST(&cbs); + { + nsAutoLock lock(mLock); + + MoveCList(rec->callbacks, cbs); + rec->addr = ai; + rec->expireTime = NowInMinutes() + mMaxCacheLifetime; + + if (rec->addr) { + // add to mEvictionQ + PR_APPEND_LINK(rec, &mEvictionQ); + NS_ADDREF(rec); + if (mEvictionQSize < mMaxCacheEntries) + mEvictionQSize++; + else { + // remove last element on mEvictionQ + nsHostRecord *tail = + NS_STATIC_CAST(nsHostRecord *, PR_LIST_TAIL(&mEvictionQ)); + PR_REMOVE_AND_INIT_LINK(tail); + PL_DHashTableOperate(&mDB, tail->host, PL_DHASH_REMOVE); + // release reference to rec owned by mEvictionQ + NS_RELEASE(tail); + } + } + } + + if (!PR_CLIST_IS_EMPTY(&cbs)) { + PRCList *node = cbs.next; + while (node != &cbs) { + nsResolveHostCB *callback = NS_STATIC_CAST(nsResolveHostCB *, node); + node = node->next; + callback->OnLookupComplete(this, rec->host, status, ai); + // NOTE: callback must not be dereferenced after this point!! + } + } + + NS_RELEASE(rec); +} + +//---------------------------------------------------------------------------- + +void PR_CALLBACK +nsHostResolver::ThreadFunc(void *arg) +{ +#if defined(RES_RETRY_ON_FAILURE) + nsResState rs; +#endif + + nsHostResolver *resolver = (nsHostResolver *) arg; + nsHostRecord *rec; + PRAddrInfo *ai; + while (resolver->GetHostToLookup(&rec)) { + LOG(("[%p] resolving %s ...\n", (void*)PR_GetCurrentThread(), rec->host)); + ai = PR_GetAddrInfoByName(rec->host, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); +#if defined(RES_RETRY_ON_FAILURE) + if (!ai && rs.Reset()) + ai = PR_GetAddrInfoByName(rec->host, PR_AF_UNSPEC, PR_AI_ADDRCONFIG); +#endif + // convert error code to nsresult. + nsresult status = ai ? NS_OK : NS_ERROR_UNKNOWN_HOST; + resolver->OnLookupComplete(rec, status, ai); + } + NS_RELEASE(resolver); +} + +//---------------------------------------------------------------------------- + +nsresult +nsHostResolver::Create(PRUint32 maxCacheEntries, + PRUint32 maxCacheLifetime, + nsHostResolver **result) +{ + nsHostResolver *res = new nsHostResolver(maxCacheEntries, + maxCacheLifetime); + if (!res) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(res); + + nsresult rv = res->Init(); + if (NS_FAILED(rv)) + NS_RELEASE(res); + + *result = res; + return rv; +} diff --git a/mozilla/netwerk/dns/src/nsHostResolver.h b/mozilla/netwerk/dns/src/nsHostResolver.h new file mode 100644 index 00000000000..4af81809791 --- /dev/null +++ b/mozilla/netwerk/dns/src/nsHostResolver.h @@ -0,0 +1,186 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsHostResolver_h__ +#define nsHostResolver_h__ + +#include "nscore.h" +#include "pratom.h" +#include "prcvar.h" +#include "prclist.h" +#include "prnetdb.h" +#include "pldhash.h" + +class nsHostResolver; +class nsHostRecord; +class nsResolveHostCB; +class nsAddrInfo; + +/* XXX move this someplace more generic */ +#define NET_DECL_REFCOUNTED_THREADSAFE \ + PRInt32 AddRef() { \ + return PR_AtomicIncrement(&mRefCount); \ + } \ + PRInt32 Release() { \ + PRInt32 n = PR_AtomicDecrement(&mRefCount); \ + if (n == 0) \ + delete this; \ + return n; \ + } + +/** + * reference counted wrapper around PRAddrInfo. these are stored in + * the DNS cache. + */ +class nsAddrInfo +{ +public: + NET_DECL_REFCOUNTED_THREADSAFE + + nsAddrInfo(PRAddrInfo *data) + : mRefCount(0) + , mData(data) {} + + const PRAddrInfo *get() const { return mData; } + +private: + nsAddrInfo(); // never called + ~nsAddrInfo() { if (mData) PR_FreeAddrInfo(mData); } + + PRInt32 mRefCount; + PRAddrInfo *mData; +}; + +/** + * ResolveHost callback object. It's PRCList members are used by + * the nsHostResolver and should not be used by anything else. + */ +class nsResolveHostCB : public PRCList +{ +public: + /** + * LookupComplete + * + * Runs on an unspecified background thread. + * + * @param resolver + * nsHostResolver object associated with this result + * @param host + * hostname that was resolved + * @param status + * if successful, |result| will be non-null + * @param result + * resulting nsAddrInfo object + */ + virtual void OnLookupComplete(nsHostResolver *resolver, + const char *host, + nsresult status, + nsAddrInfo *result) = 0; + +protected: + virtual ~nsResolveHostCB() {} +}; + +/** + * nsHostResolver: an asynchronous hostname resolver. + */ +class nsHostResolver +{ +public: + /** + * creates an addref'd instance of a nsHostResolver object. + */ + static nsresult Create(PRUint32 maxCacheEntries, // zero disables cache + PRUint32 maxCacheLifetime, // minutes + nsHostResolver **resolver); + + /** + * puts the resolver in the shutdown state, which will cause any pending + * callbacks to be detached. any future calls to ResolveHost will fail. + */ + void Shutdown(); + + /** + * host resolver instances are reference counted. + */ + NET_DECL_REFCOUNTED_THREADSAFE + + /** + * resolve the given hostname asynchronously. the caller can synthesize + * a synchronous host lookup using a lock and a cvar. as noted above + * the callback will occur re-entrantly from an unspecified thread. the + * host lookup cannot be canceled (cancelation can be layered above this + * by having the callback implementation return without doing anything). + */ + nsresult ResolveHost(const char *hostname, + PRBool bypassCache, + nsResolveHostCB *callback); + + /** + * removes the specified callback from the nsHostRecord for the given + * hostname. this function executes the callback if the callback is + * still pending with the status failure code NS_ERROR_ABORT. + */ + void DetachCallback(const char *hostname, + nsResolveHostCB *callback); + +private: + nsHostResolver(PRUint32 maxCacheEntries=50, PRUint32 maxCacheLifetime=1); + ~nsHostResolver(); + + nsresult Init(); + nsresult IssueLookup(nsHostRecord *); + PRBool GetHostToLookup(nsHostRecord **); + void OnLookupComplete(nsHostRecord *, nsresult, PRAddrInfo *); + + static void PR_CALLBACK ThreadFunc(void *); + + PRInt32 mRefCount; + PRUint32 mMaxCacheEntries; + PRUint32 mMaxCacheLifetime; + PRLock *mLock; + PRCondVar *mIdleThreadCV; // non-null if idle thread + PRBool mHaveIdleThread; + PRUint32 mThreadCount; + PLDHashTable mDB; + PRCList mPendingQ; + PRCList mEvictionQ; + PRUint32 mEvictionQSize; + PRTime mCreationTime; + PRBool mShutdown; +}; + +#endif // nsHostResolver_h__ diff --git a/mozilla/netwerk/socket/base/Makefile.in b/mozilla/netwerk/socket/base/Makefile.in index 565a2324359..bba707c00f5 100755 --- a/mozilla/netwerk/socket/base/Makefile.in +++ b/mozilla/netwerk/socket/base/Makefile.in @@ -1,3 +1,4 @@ +# vim: noexpandtab ts=4 sw=4 # # The contents of this file are subject to the Netscape Public # License Version 1.1 (the "License"); you may not use this file @@ -33,19 +34,20 @@ REQUIRES = xpcom \ string \ $(NULL) -CPPSRCS = nsSocketProviderService.cpp nsSOCKSSocketProvider.cpp nsSOCKS4SocketProvider.cpp nsSOCKSIOLayer.cpp +CPPSRCS = \ + nsSocketProviderService.cpp \ + nsSOCKSSocketProvider.cpp \ + nsSOCKSIOLayer.cpp \ + $(NULL) XPIDLSRCS = \ nsISocketProvider.idl \ nsISocketProviderService.idl \ - nsISOCKSSocketProvider.idl \ nsISOCKSSocketInfo.idl \ - nsISOCKS4SocketProvider.idl \ - nsISOCKS4SocketInfo.idl \ - nsISSLSocketProvider.idl \ nsITransportSecurityInfo.idl \ - nsISSLSocketControl.idl \ - $(NULL) + nsISSLSocketProvider.idl \ + nsISSLSocketControl.idl \ + $(NULL) ifeq ($(OS_ARCH),WINNT) NO_GEN_XPT=1 diff --git a/mozilla/netwerk/socket/base/nsISocketProvider.idl b/mozilla/netwerk/socket/base/nsISocketProvider.idl index 88bc670da98..70b8706bed6 100644 --- a/mozilla/netwerk/socket/base/nsISocketProvider.idl +++ b/mozilla/netwerk/socket/base/nsISocketProvider.idl @@ -37,36 +37,64 @@ #include "nsISupports.idl" -%{C++ -#include "prio.h" -%} +[ptr] native nsFileDescStar(struct PRFileDesc); -[ptr] native nsFileDescStar(PRFileDesc); - -[noscript, uuid(0906de00-5414-11d3-bbc8-0000861d1237)] -interface nsISocketProvider : nsISupports { - - void NewSocket(in string host, - in long port, - in string proxyHost, - in long proxyPort, - out nsFileDescStar fileDesc, - out nsISupports securityInfo ); - - void AddToSocket(in string host, - in long port, - in string proxyHost, - in long proxyPort, - in nsFileDescStar fileDesc, - out nsISupports securityInfo ); +/** + * nsISocketProvider + */ +[noscript, uuid(4c29772e-cf73-414a-98d9-661761a4511a)] +interface nsISocketProvider : nsISupports +{ + /** + * newSocket + * + * @param aFamily + * The address family for this socket (PR_AF_INET or PR_AF_INET6). + * @param aHost + * The hostname for this connection. + * @param aPort + * The port for this connection. + * @param aProxyHost + * If non-null, the proxy hostname for this connection. + * @param aProxyPort + * The proxy port for this connection. + * @param aFileDesc + * The resulting PRFileDesc. + * @param aSecurityInfo + * Any security info that should be associated with aFileDesc. This + * object typically implements nsITransportSecurityInfo. + */ + void newSocket(in long aFamily, + in string aHost, + in long aPort, + in string aProxyHost, + in long aProxyPort, + out nsFileDescStar aFileDesc, + out nsISupports aSecurityInfo); + /** + * addToSocket + * + * This function is called to allow the socket provider to layer a PRFileDesc + * on top of another PRFileDesc. For example, SSL via a SOCKS proxy. + * + * Parameters are the same as newSocket with the exception of aFileDesc, which + * is an in-param instead. + */ + void addToSocket(in long aFamily, + in string aHost, + in long aPort, + in string aProxyHost, + in long aProxyPort, + in nsFileDescStar aFileDesc, + out nsISupports aSecurityInfo); }; %{C++ -#define NS_NETWORK_SOCKET_CONTRACTID "@mozilla.org/network/socket;1" -#define NS_NETWORK_SOCKET_CONTRACTID_PREFIX NS_NETWORK_SOCKET_CONTRACTID "?type=" -#define NS_NETWORK_SOCKET_CONTRACTID_PREFIX_LENGTH 41 // strlen(NS_NETWORK_SOCKET_CONTRACTID_PREFIX) - -#define NS_ERROR_UNKNOWN_SOCKET_TYPE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 51) -#define NS_ERROR_SOCKET_CREATE_FAILED NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_NETWORK, 52) +/** + * nsISocketProvider implementations should be registered with XPCOM under a + * contract ID of the form: "@mozilla.org/network/socket;2?type=foo" + */ +#define NS_NETWORK_SOCKET_CONTRACTID_PREFIX \ + "@mozilla.org/network/socket;2?type=" %} diff --git a/mozilla/netwerk/socket/base/nsISocketProviderService.idl b/mozilla/netwerk/socket/base/nsISocketProviderService.idl index 46ad1fdc1e2..d59343516fa 100644 --- a/mozilla/netwerk/socket/base/nsISocketProviderService.idl +++ b/mozilla/netwerk/socket/base/nsISocketProviderService.idl @@ -39,21 +39,14 @@ interface nsISocketProvider; +/** + * nsISocketProviderService + * + * Provides a mapping between a socket type and its associated socket provider + * instance. One could also use the service manager directly. + */ [noscript, uuid(8f8a23d0-5472-11d3-bbc8-0000861d1237)] interface nsISocketProviderService : nsISupports { - nsISocketProvider GetSocketProvider(in string socketType); + nsISocketProvider getSocketProvider(in string socketType); }; - - -%{C++ - -#define NS_SOCKETPROVIDERSERVICE_CID \ -{ /* ed394ba0-5472-11d3-bbc8-0000861d1237 */ \ - 0xed394ba0, \ - 0x5472, \ - 0x11d3, \ - {0xbb, 0xc8, 0x00, 0x00, 0x86, 0x1d, 0x12, 0x37} \ -} - -%} diff --git a/mozilla/netwerk/socket/base/nsSOCKSIOLayer.cpp b/mozilla/netwerk/socket/base/nsSOCKSIOLayer.cpp index 8c0d0e33532..e489909dc0a 100644 --- a/mozilla/netwerk/socket/base/nsSOCKSIOLayer.cpp +++ b/mozilla/netwerk/socket/base/nsSOCKSIOLayer.cpp @@ -19,6 +19,8 @@ * * Contributor(s): * Justin Bradford + * Bradley Baetz + * Darin Fisher */ #include "nspr.h" @@ -26,7 +28,10 @@ #include "nsCRT.h" #include "nsIServiceManager.h" +#include "nsIDNSService.h" +#include "nsISOCKSSocketInfo.h" #include "nsSOCKSIOLayer.h" +#include "nsNetCID.h" static PRDescIdentity nsSOCKSIOLayerIdentity; static PRIOMethods nsSOCKSIOLayerMethods; @@ -46,145 +51,45 @@ class nsSOCKSSocketInfo : public nsISOCKSSocketInfo { public: nsSOCKSSocketInfo(); - virtual ~nsSOCKSSocketInfo(); + virtual ~nsSOCKSSocketInfo() {} NS_DECL_ISUPPORTS NS_DECL_NSISOCKSSOCKETINFO - - NS_IMETHOD GetProxyHost(char * *aProxyHost); - NS_IMETHOD SetProxyHost(const char * aProxyHost); - NS_IMETHOD GetProxyPort(PRInt32 *aProxyPort); - NS_IMETHOD SetProxyPort(PRInt32 aProxyPort); - NS_IMETHOD GetProxyType(char * *aProxyType); - NS_IMETHOD SetProxyType(const char * aProxyType); - NS_IMETHOD GetSOCKSVersion(PRInt32 *aVersion); - NS_IMETHOD SetSOCKSVersion(PRInt32 aVersion); -protected: + void Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort); - char* mProxyHost; - PRInt32 mProxyPort; - char* mProxyType; - PRInt32 mSOCKSVersion; // SOCKS version 4 or 5 (default is 5) - - // nsISOCKSSocketInfo - PRNetAddr mInternalProxyAddr; - PRNetAddr mExternalProxyAddr; - PRNetAddr mDestinationAddr; + const nsCString &ProxyHost() { return mProxyHost; } + PRInt32 ProxyPort() { return mProxyPort; } + PRInt32 Version() { return mVersion; } + +private: + nsCString mProxyHost; + PRInt32 mProxyPort; + PRInt32 mVersion; // SOCKS version 4 or 5 + PRNetAddr mInternalProxyAddr; + PRNetAddr mExternalProxyAddr; + PRNetAddr mDestinationAddr; }; nsSOCKSSocketInfo::nsSOCKSSocketInfo() -: mSOCKSVersion(-1) + : mProxyPort(-1) + , mVersion(-1) { - mProxyHost = nsnull; - mProxyPort = -1; - mProxyType = nsnull; - PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr); PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr); PR_InitializeNetAddr(PR_IpAddrAny, 0, &mDestinationAddr); } -nsSOCKSSocketInfo::~nsSOCKSSocketInfo() +void +nsSOCKSSocketInfo::Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort) { - PR_FREEIF(mProxyHost); + mVersion = version; + mProxyHost = proxyHost; + mProxyPort = proxyPort; } NS_IMPL_THREADSAFE_ISUPPORTS1(nsSOCKSSocketInfo, nsISOCKSSocketInfo) -NS_IMETHODIMP -nsSOCKSSocketInfo::GetProxyHost(char * *aProxyHost) -{ - if (!aProxyHost) return NS_ERROR_NULL_POINTER; - if (mProxyHost) - { - *aProxyHost = nsCRT::strdup(mProxyHost); - return (*aProxyHost == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; - } - else - { - *aProxyHost = nsnull; - return NS_OK; - } -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::SetProxyHost(const char * aProxyHost) -{ - PR_FREEIF(mProxyHost); - if (aProxyHost) - { - mProxyHost = nsCRT::strdup(aProxyHost); - return (mProxyHost == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; - } - else - { - mProxyHost = nsnull; - return NS_OK; - } -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::GetProxyPort(PRInt32 *aProxyPort) -{ - *aProxyPort = mProxyPort; - return NS_OK; -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::SetProxyPort(PRInt32 aProxyPort) -{ - mProxyPort = aProxyPort; - return NS_OK; -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::GetProxyType(char * *aProxyType) -{ - if (!aProxyType) return NS_ERROR_NULL_POINTER; - if (mProxyType) - { - *aProxyType = nsCRT::strdup(mProxyType); - return (*aProxyType == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; - } - else - { - *aProxyType = nsnull; - return NS_OK; - } -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::SetProxyType(const char * aProxyType) -{ - PR_FREEIF(mProxyType); - if (aProxyType) - { - mProxyType = nsCRT::strdup(aProxyType); - return (mProxyType == nsnull) ? NS_ERROR_OUT_OF_MEMORY : NS_OK; - } - else - { - mProxyType = nsnull; - return NS_OK; - } -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::GetSOCKSVersion(PRInt32 *aVersion) -{ - *aVersion = mSOCKSVersion; - return NS_OK; -} - -NS_IMETHODIMP -nsSOCKSSocketInfo::SetSOCKSVersion(PRInt32 aVersion) -{ - mSOCKSVersion = aVersion; - return NS_OK; -} - - NS_IMETHODIMP nsSOCKSSocketInfo::GetExternalProxyAddr(PRNetAddr * *aExternalProxyAddr) { @@ -561,44 +466,35 @@ nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime /*ti if (info == NULL) return PR_FAILURE; // First, we need to look up our proxy... - char scratch[PR_NETDB_BUF_SIZE]; - PRHostEnt hostentry; - nsXPIDLCString proxyHost; + const nsCString &proxyHost = info->ProxyHost(); - nsresult rv = info->GetProxyHost(getter_Copies(proxyHost)); - - if (NS_FAILED(rv) || proxyHost.IsEmpty()) { + if (proxyHost.IsEmpty()) return PR_FAILURE; - } - PRInt32 socksVersion = -1; - rv = info->GetSOCKSVersion(&socksVersion); - if (NS_FAILED(rv)) { - - return PR_FAILURE; - } + PRInt32 socksVersion = info->Version(); LOGDEBUG(("nsSOCKSIOLayerConnect SOCKS %u; proxyHost: %s.", socksVersion, proxyHost.get())); - status = PR_GetHostByName(proxyHost, scratch, PR_NETDB_BUF_SIZE, &hostentry); - - if (PR_SUCCESS != status) { - LOGERROR(("PR_GetHostByName() failed. proxyHost = %s, status = %x.",proxyHost.get(), status)); - return status; - } - - // Extract the proxy addr - PRIntn entEnum = 0; + // Sync resolve the proxy hostname. PRNetAddr proxyAddr; - PRInt32 proxyPort; - info->GetProxyPort(&proxyPort); - entEnum = PR_EnumerateHostEnt(entEnum, &hostentry, proxyPort, &proxyAddr); - - if (entEnum <= 0) { - LOGERROR(("PR_EnumerateHostEnt() failed. proxyPort = %u, entEnum = %u.", proxyPort, entEnum)); - return PR_FAILURE; + { + nsCOMPtr dns; + nsCOMPtr rec; + nsresult rv; + + dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return PR_FAILURE; + + rv = dns->Resolve(proxyHost, PR_FALSE, getter_AddRefs(rec)); + if (NS_FAILED(rv)) + return PR_FAILURE; + + rv = rec->GetNextAddr(info->ProxyPort(), &proxyAddr); + if (NS_FAILED(rv)) + return PR_FAILURE; } - + info->SetInternalProxyAddr(&proxyAddr); // For now, we'll do this as a blocking connect, @@ -663,6 +559,8 @@ nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime /*ti NS_ASSERTION((socksVersion == 4) || (socksVersion == 5), "SOCKS Version must be selected"); + nsresult rv; + // Try to connect via SOCKS 5. if (socksVersion == 5) { rv = ConnectSOCKS5(fd, addr, &extAddr, connectWait); @@ -767,101 +665,10 @@ nsSOCKSIOLayerListen(PRFileDesc *fd, PRIntn backlog) return fd->lower->methods->listen(fd->lower, backlog); } - -// create a new socket with a SOCKS IO layer -nsresult -nsSOCKSIOLayerNewSocket(const char *host, - PRInt32 port, - const char *proxyHost, - PRInt32 proxyPort, - PRInt32 socksVersion, - PRFileDesc **fd, - nsISupports** info) -{ - NS_ENSURE_TRUE((socksVersion == 4) || (socksVersion == 5), NS_ERROR_NOT_INITIALIZED); - - - if (firstTime) - { - nsSOCKSIOLayerIdentity = PR_GetUniqueIdentity("SOCKS layer"); - nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods(); - - nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect; - nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind; - nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead; - nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName; - nsSOCKSIOLayerMethods.getpeername = nsSOCKSIOLayerGetPeerName; - nsSOCKSIOLayerMethods.accept = nsSOCKSIOLayerAccept; - nsSOCKSIOLayerMethods.listen = nsSOCKSIOLayerListen; - nsSOCKSIOLayerMethods.close = nsSOCKSIOLayerClose; - - firstTime = PR_FALSE; - -#if defined(PR_LOGGING) - gSOCKSLog = PR_NewLogModule("SOCKS"); -#endif - - - } - - LOGDEBUG(("Entering nsSOCKSIOLayerNewSocket().")); - - PRFileDesc * sock; - PRFileDesc * layer; - PRStatus rv; - - /* Get a normal NSPR socket */ - sock = PR_NewTCPSocket(); - if (! sock) - { - LOGERROR(("PR_NewTCPSocket() failed")); - return NS_ERROR_OUT_OF_MEMORY; - } - - layer = PR_CreateIOLayerStub(nsSOCKSIOLayerIdentity, &nsSOCKSIOLayerMethods); - if (! layer) - { - LOGERROR(("PR_CreateIOLayerStub() failed.")); - PR_Close(sock); - return NS_ERROR_FAILURE; - } - - nsSOCKSSocketInfo * infoObject = new nsSOCKSSocketInfo(); - if (!infoObject) - { - LOGERROR(("Failed to create nsSOCKSSocketInfo().")); - PR_Close(sock); - // clean up IOLayerStub - PR_DELETE(layer); - return NS_ERROR_FAILURE; - } - - NS_ADDREF(infoObject); - infoObject->SetProxyHost(proxyHost); - infoObject->SetProxyPort(proxyPort); - infoObject->SetSOCKSVersion(socksVersion); - layer->secret = (PRFilePrivate*) infoObject; - rv = PR_PushIOLayer(sock, PR_GetLayersIdentity(sock), layer); - - if (NS_FAILED(rv)) - { - LOGERROR(("PR_PushIOLayer() failed. rv = %x.", rv)); - PR_Close(sock); - NS_RELEASE(infoObject); - PR_DELETE(layer); - return NS_ERROR_FAILURE; - } - - *fd = sock; - *info = infoObject; - NS_ADDREF(*info); - - return NS_OK; -} - // add SOCKS IO layer to an existing socket nsresult -nsSOCKSIOLayerAddToSocket(const char *host, +nsSOCKSIOLayerAddToSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, @@ -916,9 +723,7 @@ nsSOCKSIOLayerAddToSocket(const char *host, } NS_ADDREF(infoObject); - infoObject->SetProxyHost(proxyHost); - infoObject->SetProxyPort(proxyPort); - infoObject->SetSOCKSVersion(socksVersion); + infoObject->Init(socksVersion, proxyHost, proxyPort); layer->secret = (PRFilePrivate*) infoObject; rv = PR_PushIOLayer(fd, PR_GetLayersIdentity(fd), layer); @@ -934,5 +739,3 @@ nsSOCKSIOLayerAddToSocket(const char *host, NS_ADDREF(*info); return NS_OK; } - - diff --git a/mozilla/netwerk/socket/base/nsSOCKSIOLayer.h b/mozilla/netwerk/socket/base/nsSOCKSIOLayer.h index b7f652309a9..7f70ff78aa5 100644 --- a/mozilla/netwerk/socket/base/nsSOCKSIOLayer.h +++ b/mozilla/netwerk/socket/base/nsSOCKSIOLayer.h @@ -21,22 +21,15 @@ * Justin Bradford */ -#ifndef _NSSOCKSIOLAYER_H_ -#define _NSSOCKSIOLAYER_H_ +#ifndef nsSOCKSIOLayer_h__ +#define NSSOCKSIOLayer_h__ #include "prtypes.h" #include "prio.h" -#include "nsISOCKSSocketInfo.h" +#include "nscore.h" -nsresult nsSOCKSIOLayerNewSocket(const char *host, - PRInt32 port, - const char *proxyHost, - PRInt32 proxyPort, - PRInt32 socksVersion, - PRFileDesc **fd, - nsISupports **info); - -nsresult nsSOCKSIOLayerAddToSocket(const char *host, +nsresult nsSOCKSIOLayerAddToSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, @@ -44,4 +37,4 @@ nsresult nsSOCKSIOLayerAddToSocket(const char *host, PRFileDesc *fd, nsISupports **info); -#endif /* _NSSOCKSIOLAYER_H_ */ +#endif /* nsSOCKSIOLayer_h__ */ diff --git a/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.cpp b/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.cpp index 374c04c69e4..a9bd807e68c 100644 --- a/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.cpp +++ b/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.cpp @@ -19,95 +19,95 @@ * * Contributor(s): * Justin Bradford + * Darin Fisher */ -#include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsSOCKSSocketProvider.h" #include "nsSOCKSIOLayer.h" +#include "nsCOMPtr.h" +#include "nsNetError.h" ////////////////////////////////////////////////////////////////////////// -nsSOCKSSocketProvider::nsSOCKSSocketProvider() -{ -} +NS_IMPL_THREADSAFE_ISUPPORTS1(nsSOCKSSocketProvider, nsISocketProvider) -nsresult -nsSOCKSSocketProvider::Init() +NS_METHOD +nsSOCKSSocketProvider::CreateV4(nsISupports *aOuter, REFNSIID aIID, void **aResult) { - nsresult rv = NS_OK; + nsresult rv; + nsCOMPtr inst = + new nsSOCKSSocketProvider(NS_SOCKS_VERSION_4); + if (!inst) + rv = NS_ERROR_OUT_OF_MEMORY; + else + rv = inst->QueryInterface(aIID, aResult); return rv; } -nsSOCKSSocketProvider::~nsSOCKSSocketProvider() -{ -} - -NS_IMPL_THREADSAFE_ISUPPORTS2(nsSOCKSSocketProvider, nsISocketProvider, nsISOCKSSocketProvider) - NS_METHOD -nsSOCKSSocketProvider::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) +nsSOCKSSocketProvider::CreateV5(nsISupports *aOuter, REFNSIID aIID, void **aResult) { nsresult rv; - - nsSOCKSSocketProvider * inst; - - if (NULL == aResult) { - rv = NS_ERROR_NULL_POINTER; - return rv; - } - *aResult = NULL; - if (NULL != aOuter) { - rv = NS_ERROR_NO_AGGREGATION; - return rv; - } - - NS_NEWXPCOM(inst, nsSOCKSSocketProvider); - if (NULL == inst) { + nsCOMPtr inst = + new nsSOCKSSocketProvider(NS_SOCKS_VERSION_5); + if (!inst) rv = NS_ERROR_OUT_OF_MEMORY; - return rv; - } - NS_ADDREF(inst); - rv = inst->QueryInterface(aIID, aResult); - NS_RELEASE(inst); - + else + rv = inst->QueryInterface(aIID, aResult); return rv; } NS_IMETHODIMP -nsSOCKSSocketProvider::NewSocket(const char *host, +nsSOCKSSocketProvider::NewSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, - PRFileDesc **_result, + PRFileDesc **result, nsISupports **socksInfo) { - nsresult rv = nsSOCKSIOLayerNewSocket(host, - port, - proxyHost, - proxyPort, - 5, // SOCKS 5 - _result, - socksInfo); + PRFileDesc *sock; - return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; -} + sock = PR_OpenTCPSocket(family); + if (!sock) + return NS_ERROR_OUT_OF_MEMORY; -NS_IMETHODIMP -nsSOCKSSocketProvider::AddToSocket(const char *host, - PRInt32 port, - const char *proxyHost, - PRInt32 proxyPort, - PRFileDesc *socket, - nsISupports **socksInfo) -{ - nsresult rv = nsSOCKSIOLayerAddToSocket(host, + nsresult rv = nsSOCKSIOLayerAddToSocket(family, + host, port, proxyHost, proxyPort, - 5, // SOCKS 5 - socket, + mVersion, + sock, + socksInfo); + if (NS_SUCCEEDED(rv)) { + *result = sock; + return NS_OK; + } + + return NS_ERROR_SOCKET_CREATE_FAILED; +} + +NS_IMETHODIMP +nsSOCKSSocketProvider::AddToSocket(PRInt32 family, + const char *host, + PRInt32 port, + const char *proxyHost, + PRInt32 proxyPort, + PRFileDesc *sock, + nsISupports **socksInfo) +{ + nsresult rv = nsSOCKSIOLayerAddToSocket(family, + host, + port, + proxyHost, + proxyPort, + mVersion, + sock, socksInfo); - return (NS_FAILED(rv)) ? NS_ERROR_SOCKET_CREATE_FAILED : NS_OK; + if (NS_FAILED(rv)) + rv = NS_ERROR_SOCKET_CREATE_FAILED; + return rv; } diff --git a/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.h b/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.h index c9a1962717d..508b46e701c 100644 --- a/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.h +++ b/mozilla/netwerk/socket/base/nsSOCKSSocketProvider.h @@ -19,34 +19,34 @@ * * Contributor(s): * Justin Bradford + * Darin Fisher */ -#ifndef _NSSOCKSSOCKETPROVIDER_H_ -#define _NSSOCKSSOCKETPROVIDER_H_ +#ifndef nsSOCKSSocketProvider_h__ +#define nsSOCKSSocketProvider_h__ -#include "nsISOCKSSocketProvider.h" +#include "nsISocketProvider.h" +// values for ctor's |version| argument +enum { + NS_SOCKS_VERSION_4 = 4, + NS_SOCKS_VERSION_5 = 5 +}; -/* 8dbe7246-1dd2-11b2-9b8f-b9a849e4403a */ -#define NS_SOCKSSOCKETPROVIDER_CID { 0x8dbe7246, 0x1dd2, 0x11b2, {0x9b, 0x8f, 0xb9, 0xa8, 0x49, 0xe4, 0x40, 0x3a}} - -class nsSOCKSSocketProvider : public nsISOCKSSocketProvider +class nsSOCKSSocketProvider : public nsISocketProvider { public: NS_DECL_ISUPPORTS NS_DECL_NSISOCKETPROVIDER - NS_DECL_NSISOCKSSOCKETPROVIDER - // nsSOCKSSocketProvider methods: - nsSOCKSSocketProvider(); - virtual ~nsSOCKSSocketProvider(); + nsSOCKSSocketProvider(PRUint32 version) : mVersion(version) {} + virtual ~nsSOCKSSocketProvider() {} - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); + static NS_METHOD CreateV4(nsISupports *, REFNSIID aIID, void **aResult); + static NS_METHOD CreateV5(nsISupports *, REFNSIID aIID, void **aResult); - nsresult Init(); - -protected: +private: + PRUint32 mVersion; // NS_SOCKS_VERSION_4 or 5 }; -#endif /* _NSSOCKSSOCKETPROVIDER_H_ */ +#endif /* nsSOCKSSocketProvider_h__ */ diff --git a/mozilla/netwerk/socket/base/nsSocketProviderService.cpp b/mozilla/netwerk/socket/base/nsSocketProviderService.cpp index 3e93a25cad6..b7f7aec067d 100644 --- a/mozilla/netwerk/socket/base/nsSocketProviderService.cpp +++ b/mozilla/netwerk/socket/base/nsSocketProviderService.cpp @@ -37,48 +37,21 @@ #include "nsString.h" #include "nsIServiceManager.h" - -#include "nsSocketProviderService.h" #include "nsISocketProvider.h" +#include "nsSocketProviderService.h" +#include "nsNetError.h" //////////////////////////////////////////////////////////////////////////////// -nsSocketProviderService::nsSocketProviderService() -{ -} - -nsresult -nsSocketProviderService::Init() -{ - return NS_OK; -} - -nsSocketProviderService::~nsSocketProviderService() -{ -} - NS_METHOD nsSocketProviderService::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) { nsresult rv; - - if (aOuter) - return NS_ERROR_NO_AGGREGATION; - - nsSocketProviderService* pSockProvServ = new nsSocketProviderService(); - if (pSockProvServ == nsnull) - return NS_ERROR_OUT_OF_MEMORY; - - NS_ADDREF(pSockProvServ); - rv = pSockProvServ->Init(); - if (NS_FAILED(rv)) - { - delete pSockProvServ; - return rv; - } - rv = pSockProvServ->QueryInterface(aIID, aResult); - NS_RELEASE(pSockProvServ); - + nsCOMPtr inst = new nsSocketProviderService(); + if (!inst) + rv = NS_ERROR_OUT_OF_MEMORY; + else + rv = inst->QueryInterface(aIID, aResult); return rv; } @@ -87,19 +60,18 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(nsSocketProviderService, nsISocketProviderService) //////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP -nsSocketProviderService::GetSocketProvider(const char *aSocketType, nsISocketProvider **_result) +nsSocketProviderService::GetSocketProvider(const char *type, + nsISocketProvider **result) { nsresult rv; - nsCAutoString contractID( - nsDependentCString(NS_NETWORK_SOCKET_CONTRACTID_PREFIX) + - nsDependentCString(aSocketType)); + NS_LITERAL_CSTRING(NS_NETWORK_SOCKET_CONTRACTID_PREFIX) + + nsDependentCString(type)); - rv = CallGetService(contractID.get(), _result); + rv = CallGetService(contractID.get(), result); if (NS_FAILED(rv)) - return NS_ERROR_UNKNOWN_SOCKET_TYPE; - - return NS_OK; + rv = NS_ERROR_UNKNOWN_SOCKET_TYPE; + return rv; } //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/netwerk/socket/base/nsSocketProviderService.h b/mozilla/netwerk/socket/base/nsSocketProviderService.h index 370898dde34..ddbcd15ca2c 100644 --- a/mozilla/netwerk/socket/base/nsSocketProviderService.h +++ b/mozilla/netwerk/socket/base/nsSocketProviderService.h @@ -35,8 +35,8 @@ * * ***** END LICENSE BLOCK ***** */ -#ifndef _NSSOCKETPROVIDERSERVICE_H_ -#define _NSSOCKETPROVIDERSERVICE_H_ +#ifndef nsSocketProviderService_h__ +#define nsSocketProviderService_h__ #include "nsISocketProviderService.h" @@ -44,19 +44,12 @@ class nsSocketProviderService : public nsISocketProviderService { public: NS_DECL_ISUPPORTS - NS_DECL_NSISOCKETPROVIDERSERVICE - // nsISocketProviderService methods: - nsSocketProviderService(); - virtual ~nsSocketProviderService(); + nsSocketProviderService() {} + virtual ~nsSocketProviderService() {} - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); - - nsresult Init(); - -protected: + static NS_METHOD Create(nsISupports *, REFNSIID aIID, void **aResult); }; -#endif /* _NSSOCKETPROVIDERSERVICE_H */ +#endif /* nsSocketProviderService_h__ */ diff --git a/mozilla/netwerk/test/Makefile.in b/mozilla/netwerk/test/Makefile.in index ac472657830..c564c4ccb3b 100644 --- a/mozilla/netwerk/test/Makefile.in +++ b/mozilla/netwerk/test/Makefile.in @@ -1,3 +1,4 @@ +# vim: noexpandtab ts=8 sw=8 # # The contents of this file are subject to the Netscape Public # License Version 1.1 (the "License"); you may not use this file @@ -33,55 +34,43 @@ REQUIRES = xpcom \ util \ $(NULL) -CPPSRCS = \ - PropertiesTest.cpp \ - urltest.cpp \ - TestCallbacks.cpp \ - TestPageLoad.cpp \ - TestPerf.cpp \ - TestIDN.cpp \ - TestURLParser.cpp \ - TestStandardURL.cpp \ - TestSocketTransport.cpp \ - TestUpload.cpp \ - TestStreamTransport.cpp \ - TestStreamChannel.cpp \ - TestStreamPump.cpp \ - TestProtocols.cpp \ - TestBlockingSocket.cpp \ - $(NULL) - -# TestHttp.cpp \ -# TestFileInput.cpp \ -# TestFileInput2.cpp \ -# TestMCTransport.cpp \ -# TestSocketIO.cpp \ -# TestSocketInput.cpp \ -# TestSocketTransport.cpp \ -# TestFileTransport.cpp +CPPSRCS = PropertiesTest.cpp \ + urltest.cpp \ + TestCallbacks.cpp \ + TestPageLoad.cpp \ + TestPerf.cpp \ + TestIDN.cpp \ + TestURLParser.cpp \ + TestStandardURL.cpp \ + TestSocketTransport.cpp \ + TestUpload.cpp \ + TestStreamTransport.cpp \ + TestStreamChannel.cpp \ + TestStreamPump.cpp \ + TestProtocols.cpp \ + TestBlockingSocket.cpp \ + TestDNS.cpp \ + $(NULL) SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX)) include $(topsrcdir)/config/config.mk -LIBS = \ - $(EXTRA_DSO_LIBS) \ - $(MOZ_JS_LIBS) \ - $(XPCOM_LIBS) \ - $(NSPR_LIBS) \ - $(NULL) +LIBS = $(EXTRA_DSO_LIBS) \ + $(MOZ_JS_LIBS) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) include $(topsrcdir)/config/rules.mk -_RES_FILES = \ - urlparse.dat \ - urlparse_unx.dat \ - jarlist.dat \ - $(NULL) +_RES_FILES = urlparse.dat \ + urlparse_unx.dat \ + jarlist.dat \ + $(NULL) libs:: $(_RES_FILES) $(INSTALL) $^ $(DIST)/bin/res install:: $(_RES_FILES) $(SYSINSTALL) $(IFLAGS1) $^ $(DESTDIR)$(mozappdir)/res - diff --git a/mozilla/netwerk/test/TestDNS.cpp b/mozilla/netwerk/test/TestDNS.cpp new file mode 100644 index 00000000000..98f6392d51f --- /dev/null +++ b/mozilla/netwerk/test/TestDNS.cpp @@ -0,0 +1,126 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is IBM Corporation. + * Portions created by IBM Corporation are Copyright (C) 2003 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * IBM Corp. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include "nsIServiceManager.h" +#include "nsIDNSService.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsNetCID.h" +#include "prinrval.h" +#include "prthread.h" +#include "prnetdb.h" +#include "nsCRT.h" + +class myDNSListener : public nsIDNSListener +{ +public: + NS_DECL_ISUPPORTS + + myDNSListener(const char *host, PRInt32 index) + : mHost(host) + , mIndex(index) {} + virtual ~myDNSListener() {} + + NS_IMETHOD OnLookupComplete(nsIDNSRequest *request, + nsIDNSRecord *rec, + nsresult status) + { + printf("%d: OnLookupComplete called [host=%s status=%x ai=%p]\n", + mIndex, mHost.get(), status, (void*)rec); + + if (NS_SUCCEEDED(status)) { + nsCAutoString buf; + + rec->GetCanonicalName(buf); + printf("%d: canonname=%s\n", mIndex, buf.get()); + + while (NS_SUCCEEDED(rec->GetNextAddrAsString(buf))) + printf("%d: => %s\n", mIndex, buf.get()); + } + + return NS_OK; + } + +private: + nsCString mHost; + PRInt32 mIndex; +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(myDNSListener, nsIDNSListener) + +int main(int argc, char **argv) +{ + int sleepLen = 10; // default: 10 seconds + + if (argc == 1) { + printf("usage: TestDNS [-N] hostname1 [hostname2 ...]\n"); + return -1; + } + + nsCOMPtr dns = do_GetService(NS_DNSSERVICE_CONTRACTID); + if (!dns) + return -1; + + if (argv[1][0] == '-') { + sleepLen = atoi(argv[1]+1); + argv++; + argc--; + } + + for (int j=0; j<2; ++j) { + for (int i=1; i listener = new myDNSListener(argv[i], i); + nsCOMPtr req; + dns->AsyncResolve(hostBuf, PR_FALSE, listener, nsnull, getter_AddRefs(req)); + } + + printf("main thread sleeping for %d seconds...\n", sleepLen); + PR_Sleep(PR_SecondsToInterval(sleepLen)); + } + + printf("shutting down main thread...\n"); + dns->Shutdown(); + return 0; +} diff --git a/mozilla/security/manager/ssl/src/nsNSSIOLayer.cpp b/mozilla/security/manager/ssl/src/nsNSSIOLayer.cpp index 535c9541e76..6b8d77f7e09 100644 --- a/mozilla/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/mozilla/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -1199,7 +1199,8 @@ static void InitNSSMethods() } nsresult -nsSSLIOLayerNewSocket(const char *host, +nsSSLIOLayerNewSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, @@ -1217,10 +1218,10 @@ nsSSLIOLayerNewSocket(const char *host, firstTime = PR_FALSE; } - PRFileDesc* sock = PR_OpenTCPSocket(PR_AF_INET6); + PRFileDesc* sock = PR_OpenTCPSocket(family); if (!sock) return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = nsSSLIOLayerAddToSocket(host, port, proxyHost, proxyPort, + nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort, sock, info, forSTARTTLS); if (NS_FAILED(rv)) { PR_Close(sock); @@ -2326,7 +2327,8 @@ nsSSLIOLayerSetOptions(PRFileDesc *fd, PRBool forSTARTTLS, } nsresult -nsSSLIOLayerAddToSocket(const char* host, +nsSSLIOLayerAddToSocket(PRInt32 family, + const char* host, PRInt32 port, const char* proxyHost, PRInt32 proxyPort, diff --git a/mozilla/security/manager/ssl/src/nsNSSIOLayer.h b/mozilla/security/manager/ssl/src/nsNSSIOLayer.h index 75558dc58b7..07259920b49 100644 --- a/mozilla/security/manager/ssl/src/nsNSSIOLayer.h +++ b/mozilla/security/manager/ssl/src/nsNSSIOLayer.h @@ -111,7 +111,8 @@ private: void destructorSafeDestroyNSSReference(); }; -nsresult nsSSLIOLayerNewSocket(const char *host, +nsresult nsSSLIOLayerNewSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, @@ -119,7 +120,8 @@ nsresult nsSSLIOLayerNewSocket(const char *host, nsISupports **securityInfo, PRBool forSTARTTLS); -nsresult nsSSLIOLayerAddToSocket(const char *host, +nsresult nsSSLIOLayerAddToSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, diff --git a/mozilla/security/manager/ssl/src/nsSSLSocketProvider.cpp b/mozilla/security/manager/ssl/src/nsSSLSocketProvider.cpp index 9cc59cce127..ef5b1092abb 100644 --- a/mozilla/security/manager/ssl/src/nsSSLSocketProvider.cpp +++ b/mozilla/security/manager/ssl/src/nsSSLSocketProvider.cpp @@ -23,6 +23,7 @@ #include "nsSSLSocketProvider.h" #include "nsNSSIOLayer.h" +#include "nsNetError.h" nsSSLSocketProvider::nsSSLSocketProvider() { @@ -36,14 +37,16 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsSSLSocketProvider, nsISocketProvider, nsISSLSocketProvider) NS_IMETHODIMP -nsSSLSocketProvider::NewSocket(const char *host, +nsSSLSocketProvider::NewSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, PRFileDesc **_result, nsISupports **securityInfo) { - nsresult rv = nsSSLIOLayerNewSocket(host, + nsresult rv = nsSSLIOLayerNewSocket(family, + host, port, proxyHost, proxyPort, @@ -55,14 +58,16 @@ nsSSLSocketProvider::NewSocket(const char *host, // Add the SSL IO layer to an existing socket NS_IMETHODIMP -nsSSLSocketProvider::AddToSocket(const char *host, +nsSSLSocketProvider::AddToSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, PRFileDesc *aSocket, nsISupports **securityInfo) { - nsresult rv = nsSSLIOLayerAddToSocket(host, + nsresult rv = nsSSLIOLayerAddToSocket(family, + host, port, proxyHost, proxyPort, diff --git a/mozilla/security/manager/ssl/src/nsTLSSocketProvider.cpp b/mozilla/security/manager/ssl/src/nsTLSSocketProvider.cpp index 0042e2c941f..6ef61b826df 100644 --- a/mozilla/security/manager/ssl/src/nsTLSSocketProvider.cpp +++ b/mozilla/security/manager/ssl/src/nsTLSSocketProvider.cpp @@ -23,6 +23,7 @@ #include "nsTLSSocketProvider.h" #include "nsNSSIOLayer.h" +#include "nsNetError.h" nsTLSSocketProvider::nsTLSSocketProvider() { @@ -36,14 +37,16 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsTLSSocketProvider, nsISocketProvider, nsISSLSocketProvider) NS_IMETHODIMP -nsTLSSocketProvider::NewSocket(const char *host, +nsTLSSocketProvider::NewSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, PRFileDesc **_result, nsISupports **securityInfo) { - nsresult rv = nsSSLIOLayerNewSocket(host, + nsresult rv = nsSSLIOLayerNewSocket(family, + host, port, proxyHost, proxyPort, @@ -56,14 +59,16 @@ nsTLSSocketProvider::NewSocket(const char *host, // Add the SSL IO layer to an existing socket NS_IMETHODIMP -nsTLSSocketProvider::AddToSocket(const char *host, +nsTLSSocketProvider::AddToSocket(PRInt32 family, + const char *host, PRInt32 port, const char *proxyHost, PRInt32 proxyPort, PRFileDesc *aSocket, nsISupports **securityInfo) { - nsresult rv = nsSSLIOLayerAddToSocket(host, + nsresult rv = nsSSLIOLayerAddToSocket(family, + host, port, proxyHost, proxyPort,