Basic Mac implementation of async DNS. r=warren, patrick; part of bug:10731.

This commit is contained in:
gordon%netscape.com 1999-11-03 01:24:51 +00:00
Родитель 122fb95337
Коммит 67c770c6b8
4 изменённых файлов: 486 добавлений и 101 удалений

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

@ -24,6 +24,8 @@
typedef struct nsHostEnt
{
PRHostEnt hostEnt;
PRIntn bufLen;
char * bufPtr;
char buffer[PR_NETDB_BUF_SIZE];
} nsHostEnt;
%}

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

@ -16,95 +16,115 @@
* Reserved.
*/
#include "nsCOMPtr.h"
#include "nsDnsService.h"
#include "nsIDNSListener.h"
#include "nsIRequest.h"
#include "nsISupportsArray.h"
#include "nsError.h"
#include "prnetdb.h"
#include "nsString2.h"
#if defined(XP_MAC)
#include "pprthred.h"
static pascal void DNSNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
#if TARGET_CARBON
#define nsDNS_NOTIFIER_ROUTINE nsDnsServiceNotifierRoutineUPP
#define INIT_OPEN_TRANSPORT() InitOpenTransport(mClientContext, kInitOTForExtensionMask)
#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err, mClientContext)
#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err, mClientContext)
#else
#define nsDNS_NOTIFIER_ROUTINE nsDnsServiceNotifierRoutine
#define INIT_OPEN_TRANSPORT() InitOpenTransport()
#define OT_OPEN_INTERNET_SERVICES(config, flags, err) OTOpenInternetServices(config, flags, err)
#define OT_OPEN_ENDPOINT(config, flags, info, err) OTOpenEndpoint(config, flags, info, err)
#endif /* TARGET_CARBON */
#endif /* XP_MAC */
////////////////////////////////////////////////////////////////////////////////
class nsDNSRequest;
class nsDNSLookup;
class nsDNSLookup
#if defined(XP_MAC)
typedef struct nsInetHostInfo {
InetHostInfo hostInfo;
nsDNSLookup * lookup;
} nsInetHostInfo;
typedef struct nsLookupElement {
QElem qElem;
nsDNSLookup * lookup;
} nsLookupElement;
#endif
class nsDNSLookup : public nsISupports
{
public:
nsresult AddDNSRequest(nsDNSRequest* request);
NS_DECL_ISUPPORTS
const char* mHostName;
PRHostEnt mHostEntry; // NSPR or platform specific hostent?
PRIntn mCount;
PRBool mComplete;
PRIntn mIndex; // XXX - for round robin
void * mListenerQueue; // XXX - maintain a list of nsDNSRequests.
nsDNSLookup(nsISupports * clientContext, const char * hostName, nsIDNSListener* listener);
~nsDNSLookup(void);
nsresult AddDNSRequest(nsDNSRequest* request);
nsresult FinishHostEntry(void);
nsresult CallOnFound(void);
const char * HostName(void) { return mHostName; }
nsresult InitiateDNSLookup(nsDNSService * dnsService);
protected:
friend pascal void nsDnsServiceNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
char * mHostName;
nsHostEnt mHostEntry;
PRBool mComplete;
nsresult mResult;
PRIntn mCount;
PRIntn mIndex; // XXX - for round robin
nsCOMPtr<nsISupportsArray> mRequestQueue; // XXX - maintain a list of nsDNSRequests.
#if defined(XP_MAC)
nsLookupElement mLookupElement;
nsInetHostInfo mInetHostInfo;
nsIDNSListener * mListener; // belongs with nsDNSRequest
nsISupports * mContext; // belongs with nsDNSRequest
#endif
};
NS_IMPL_ISUPPORTS1(nsDNSLookup, nsISupports)
class nsDNSRequest : public nsIRequest
{
nsIDNSListener* mListener;
nsDNSLookup* mHostNameLookup;
// nsIRequest methods:
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUEST
protected:
nsCOMPtr<nsIDNSListener> mListener;
nsCOMPtr<nsISupports> mContext;
nsDNSLookup* mHostNameLookup;
};
NS_IMPL_ISUPPORTS1(nsDNSRequest, nsIRequest)
////////////////////////////////////////////////////////////////////////////////
// nsDNSService methods:
nsDNSService::nsDNSService()
{
NS_INIT_REFCNT();
}
nsresult
nsDNSService::Init()
{
// initialize DNS cache (persistent?)
#if defined(XP_MAC)
// create Open Transport Service Provider for DNS Lookups
#elif defined(_WIN)
// create DNS EventHandler Window
#elif defined(XP_UNIX)
// XXXX - ?
#endif
return NS_OK;
}
nsDNSService::~nsDNSService()
{
// deallocate cache
#if defined(XP_MAC)
// deallocate Open Transport Service Provider
#elif defined(_WIN)
// dispose DNS EventHandler Window
#elif defined(XP_UNIX)
// XXXX - ?
#endif
}
NS_IMPL_ISUPPORTS(nsDNSService, NS_GET_IID(nsIDNSService));
NS_METHOD
nsDNSService::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
{
nsDNSService* ph = new nsDNSService();
if (ph == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(ph);
nsresult rv = ph->QueryInterface(aIID, aResult);
NS_RELEASE(ph);
return rv;
}
// utility routines:
////////////////////////////////////////////////////////////////////////////////
// nsIDNSService methods:
//
// Allocate space from the buffer, aligning it to "align" before doing
// the allocation. "align" must be a power of 2.
@ -129,47 +149,389 @@ static char *BufAlloc(PRIntn amount, char **bufp, PRIntn *buflenp, PRIntn align)
return buf;
}
////////////////////////////////////////////////////////////////////////////////
// nsDNSLookup methods:
////////////////////////////////////////////////////////////////////////////////
nsDNSLookup::nsDNSLookup(nsISupports * clientContext, const char * hostName, nsIDNSListener* listener)
{
mHostName = new char [PL_strlen(hostName) + 1];
PL_strcpy(mHostName, hostName);
mHostEntry.bufLen = PR_NETDB_BUF_SIZE;
mHostEntry.bufPtr = mHostEntry.buffer;
mCount = 0;
mComplete = PR_FALSE;
mResult = NS_OK;
mIndex = 0;
mRequestQueue = nsnull;
#if defined(XP_MAC)
mInetHostInfo.lookup = this;
mLookupElement.lookup = this;
mContext = clientContext; // belongs with nsDNSRequest
mListener = listener; // belongs with nsDNSRequest
#endif
}
nsDNSLookup::~nsDNSLookup(void)
{
if (mHostName)
delete [] mHostName;
}
nsresult
nsDNSLookup::AddDNSRequest(nsDNSRequest* request)
{
return NS_OK;
}
nsresult
nsDNSLookup::FinishHostEntry(void)
{
#if defined(XP_MAC)
PRIntn len, count, i;
// convert InetHostInfo to PRHostEnt
// copy name
len = nsCRT::strlen(mInetHostInfo.hostInfo.name);
mHostEntry.hostEnt.h_name = BufAlloc(len, &mHostEntry.bufPtr, &mHostEntry.bufLen, 0);
NS_ASSERTION(nsnull != mHostEntry.hostEnt.h_name,"nsHostEnt buffer full.");
if (mHostEntry.hostEnt.h_name == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
nsCRT::memcpy(mHostEntry.hostEnt.h_name, mInetHostInfo.hostInfo.name, len);
// set aliases to nsnull
mHostEntry.hostEnt.h_aliases = (char **)BufAlloc(sizeof(char *), &mHostEntry.bufPtr, &mHostEntry.bufLen, sizeof(char *));
NS_ASSERTION(nsnull != mHostEntry.hostEnt.h_aliases,"nsHostEnt buffer full.");
if (mHostEntry.hostEnt.h_aliases == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
*mHostEntry.hostEnt.h_aliases = nsnull;
// fill in address type
mHostEntry.hostEnt.h_addrtype = AF_INET;
// set address length
mHostEntry.hostEnt.h_length = sizeof(long);
// count addresses and allocate storage for the pointers
for (count = 1; count < kMaxHostAddrs && mInetHostInfo.hostInfo.addrs[count] != nsnull; count++){;}
mHostEntry.hostEnt.h_addr_list = (char **)BufAlloc(count * sizeof(char *), &mHostEntry.bufPtr, &mHostEntry.bufLen, sizeof(char *));
NS_ASSERTION(nsnull != mHostEntry.hostEnt.h_addr_list,"nsHostEnt buffer full.");
if (mHostEntry.hostEnt.h_addr_list == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
// copy addresses one at a time
len = mHostEntry.hostEnt.h_length;
for (i = 0; i < kMaxHostAddrs && mInetHostInfo.hostInfo.addrs[i] != nsnull; i++) {
mHostEntry.hostEnt.h_addr_list[i] = BufAlloc(len, &mHostEntry.bufPtr, &mHostEntry.bufLen, len);
NS_ASSERTION(nsnull != mHostEntry.hostEnt.h_addr_list[i],"nsHostEnt buffer full.");
if (mHostEntry.hostEnt.h_addr_list[i] == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
*(InetHost *)mHostEntry.hostEnt.h_addr_list[i] = mInetHostInfo.hostInfo.addrs[i];
}
#endif
mComplete = PR_TRUE;
return NS_OK;
}
nsresult
nsDNSLookup::CallOnFound(void)
{
nsresult result;
// iterate through request queue calling listeners
// but for now just do this
if (NS_SUCCEEDED(mResult)) {
result = mListener->OnFound(mContext, mHostName, &mHostEntry);
}
result = mListener->OnStopLookup(mContext, mHostName, mResult);
return result;
}
nsresult
nsDNSLookup::InitiateDNSLookup(nsDNSService * dnsService) // I don't want to have to pass this in...
{
nsresult rv = NS_OK;
#if defined(XP_MAC)
OSErr err;
err = OTInetStringToAddress(dnsService->mServiceRef, (char *)mHostName, (InetHostInfo *)&mInetHostInfo);
if (err != noErr)
rv = NS_ERROR_UNEXPECTED;
#endif
return rv;
}
////////////////////////////////////////////////////////////////////////////////
// nsDNSService methods:
////////////////////////////////////////////////////////////////////////////////
#if defined(XP_MAC)
pascal void nsDnsServiceNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
pascal void nsDnsServiceNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie)
{
#pragma unused(contextPtr)
if (code == T_DNRSTRINGTOADDRCOMPLETE) {
nsDNSService * dnsService = (nsDNSService *)contextPtr;
nsDNSLookup * dnsLookup = ((nsInetHostInfo *)cookie)->lookup;
PRThread * thread;
if (result != kOTNoError)
dnsLookup->mResult = NS_ERROR_UNKNOWN_HOST;
// queue result & wake up dns service thread
Enqueue((QElem *)&dnsLookup->mLookupElement, &dnsService->mCompletionQueue);
dnsService->mThread->GetPRThread(&thread);
if (thread)
PR_Mac_PostAsyncNotify(thread);
}
// or else we don't handle the event
}
#endif
nsDNSService::nsDNSService()
{
NS_INIT_REFCNT();
mThreadRunning = PR_FALSE;
mThread = nsnull;
#if defined(XP_MAC)
mServiceRef = nsnull;
mCompletionQueue.qFlags = 0;
mCompletionQueue.qHead = nsnull;
mCompletionQueue.qTail = nsnull;
#if TARGET_CARBON
mCLientContext = nsnull;
#endif /* TARGET_CARBON */
#endif /* defined(XP_MAC) */
}
nsresult
nsDNSService::Init()
{
nsresult rv = NS_OK;
// initialize DNS cache (persistent?)
#if defined(XP_MAC)
// create Open Transport Service Provider for DNS Lookups
OSStatus errOT;
#if TARGET_CARBON
nsDnsServiceNotifierRoutineUPP = NewOTNotifyUPP(nsDnsServiceNotifierRoutine);
errOT = OTAllocClientContext((UInt32)0, &clientContext);
NS_ASSERTION(err == kOTNoError, "error allocating OTClientContext.");
#endif
errOT = INIT_OPEN_TRANSPORT();
NS_ASSERTION(errOT == kOTNoError, "InitOpenTransport failed.");
mServiceRef = OT_OPEN_INTERNET_SERVICES(kDefaultInternetServicesPath, NULL, &errOT);
if (errOT != kOTNoError) return NS_ERROR_UNEXPECTED; /* no network -- oh well */
NS_ASSERTION((mServiceRef != NULL) && (errOT == kOTNoError), "error opening OT service.");
/* Install notify function for DNR Address To String completion */
errOT = OTInstallNotifier(mServiceRef, nsDNS_NOTIFIER_ROUTINE, this);
NS_ASSERTION(errOT == kOTNoError, "error installing dns notification routine.");
/* Put us into async mode */
errOT = OTSetAsynchronous(mServiceRef);
NS_ASSERTION(errOT == kOTNoError, "error setting service to async mode.");
// if either of the two previous calls failed then dealloc service ref and return NS_FAILED
rv = NS_NewThread(&mThread, this, 0, PR_JOINABLE_THREAD);
#elif defined(_WIN)
// create DNS EventHandler Window
#elif defined(XP_UNIX)
// XXXX - ?
#endif
return NS_OK;
}
nsDNSService::~nsDNSService()
{
// deallocate cache
#if defined(XP_MAC)
CloseOpenTransport(); // should be moved to terminate routine
// deallocate Open Transport Service Provider
#elif defined(_WIN)
// dispose DNS EventHandler Window
#elif defined(XP_UNIX)
// XXXX - ?
#endif
}
NS_IMPL_ISUPPORTS2(nsDNSService, nsIDNSService, nsIRunnable);
NS_METHOD
nsDNSService::Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult)
{
nsresult rv;
if (aOuter != nsnull)
return NS_ERROR_NO_AGGREGATION;
nsDNSService* dnsService = new nsDNSService();
if (dnsService == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(dnsService);
rv = dnsService->Init();
if (NS_SUCCEEDED(rv)) {
rv = dnsService->QueryInterface(aIID, aResult);
}
NS_RELEASE(dnsService);
return rv;
}
//
// --------------------------------------------------------------------------
// nsIRunnable implementation...
// --------------------------------------------------------------------------
//
NS_IMETHODIMP
nsDNSService::Lookup(nsISupports* ctxt,
const char* hostname,
nsDNSService::Run(void)
{
#if defined(XP_MAC)
OSErr err;
nsLookupElement * lookupElement;
nsDNSLookup * lookup;
nsresult rv;
mThreadRunning = PR_TRUE;
while (mThreadRunning) {
PR_Mac_WaitForAsyncNotify(PR_INTERVAL_NO_TIMEOUT);
// check queue for completed DNS lookups
while ((lookupElement = (nsLookupElement *)mCompletionQueue.qHead) != nsnull) {
err = Dequeue((QElemPtr)lookupElement, &mCompletionQueue);
if (err)
continue; // assert
lookup = lookupElement->lookup;
// convert InetHostInfo to nsHostEnt
rv = lookup->FinishHostEntry();
if (NS_SUCCEEDED(rv)) {
// put lookup in cache
}
// issue callbacks
rv = lookup->CallOnFound();
delete lookup; // until we start caching them
}
}
#endif
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// nsIDNSService methods:
////////////////////////////////////////////////////////////////////////////////
NS_IMETHODIMP
nsDNSService::Lookup(nsISupports* clientContext,
const char* hostName,
nsIDNSListener* listener,
nsIRequest* *DNSRequest)
{
nsresult rv, result = NS_OK;
// initateLookupNeeded = false;
// lock dns service
// search cache for existing nsDNSLookup with matching hostname
// if (exists) {
// if (complete) {
// AddRef lookup
// unlock cache
// OnStartLookup
// OnFound
// OnStopLookup
// Release lookup
// return
// }
// } else {
// create nsDNSLookup
// iniateLookupNeeded = true
// }
// create nsDNSRequest & queue on nsDNSLookup
// unlock dns service
// OnStartLookup
// if (iniateLookupNeeded) {
// initiate async lookup
// }
//
#if defined(XP_MAC)
// create nsDNSLookup
nsDNSLookup * lookup = new nsDNSLookup(clientContext, hostName, listener);
if (lookup == nsnull)
return NS_ERROR_OUT_OF_MEMORY;
rv = listener->OnStartLookup(clientContext, hostName);
// what do we do with the return value here?
// initiate async lookup
rv = lookup->InitiateDNSLookup(this);
return rv;
#else
// temporary SYNC version
PRStatus status = PR_SUCCESS;
nsHostEnt* hostentry;
/*
check cache for existing nsDNSLookup with matching hostname
call OnStartLookup
if (nsDNSLookup doesn't exist) {
create nsDNSLookup for this hostname
kick off DNS Lookup
}
if (nsDNSLookup already has at least one address) {
call OnFound
}
if (nsDNSLookup is already complete) {
call OnStopLookup
return null
}
create nsDNSRequest
queue nsDNSRequest on nsDNSLookup // XXXX - potential race condition here
return nsDNSRequest
*/
// temporary SYNC version
hostentry = new nsHostEnt;
if (!hostentry)
return NS_ERROR_OUT_OF_MEMORY;
rv = listener->OnStartLookup(ctxt, hostname);
rv = listener->OnStartLookup(ctxt, hostName);
PRBool numeric = PR_TRUE;
for (const char *hostCheck = hostname; *hostCheck; hostCheck++) {
for (const char *hostCheck = hostName; *hostCheck; hostCheck++) {
if (!nsString2::IsDigit(*hostCheck) && (*hostCheck != '.') ) {
numeric = PR_FALSE;
break;
@ -181,17 +543,17 @@ nsDNSService::Lookup(nsISupports* ctxt,
if (numeric) {
// If it is numeric then try to convert it into an IP-Address
netAddr = (PRNetAddr*)nsAllocator::Alloc(sizeof(PRNetAddr));
status = PR_StringToNetAddr(hostname, netAddr);
status = PR_StringToNetAddr(hostName, netAddr);
if (PR_SUCCESS == status) {
// slam the IP in and move on.
PRHostEnt *ent = &(hostentry->hostEnt);
PRIntn bufLen = PR_NETDB_BUF_SIZE;
char *buffer = hostentry->buffer;
ent->h_name = (char*)BufAlloc(PL_strlen(hostname) + 1,
ent->h_name = (char*)BufAlloc(PL_strlen(hostName) + 1,
&buffer,
&bufLen,
0);
memcpy(ent->h_name, hostname, PL_strlen(hostname) + 1);
memcpy(ent->h_name, hostName, PL_strlen(hostName) + 1);
ent->h_aliases = (char**)BufAlloc(1 * sizeof(char*),
&buffer,
@ -215,21 +577,21 @@ nsDNSService::Lookup(nsISupports* ctxt,
// If the hostname is numeric, but we couldn't create
// a net addr out of it, we're dealing w/ a purely numeric
// address (no dots), try a regular gethostbyname on it.
status = PR_GetHostByName(hostname,
status = PR_GetHostByName(hostName,
hostentry->buffer,
PR_NETDB_BUF_SIZE,
&hostentry->hostEnt);
}
nsAllocator::Free(netAddr);
} else {
status = PR_GetHostByName(hostname,
status = PR_GetHostByName(hostName,
hostentry->buffer,
PR_NETDB_BUF_SIZE,
&hostentry->hostEnt);
}
if (PR_SUCCESS == status) {
rv = listener->OnFound(ctxt, hostname, hostentry);
rv = listener->OnFound(ctxt, hostName, hostentry);
result = NS_OK;
}
else {
@ -239,7 +601,8 @@ nsDNSService::Lookup(nsISupports* ctxt,
// listener does not need to copy it...
delete hostentry;
rv = listener->OnStopLookup(ctxt, hostname, result);
rv = listener->OnStopLookup(ctxt, hostName, result);
return result;
#endif
}

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

@ -20,7 +20,10 @@
#define nsDNSService_h__
#include "nsIDNSService.h"
#include "nsIRunnable.h"
#include "nsIThread.h"
#if defined(XP_MAC)
#include <OSUtils.h>
#include <OpenTransport.h>
#include <OpenTptInternet.h>
#elif defined (XP_PC)
@ -29,11 +32,15 @@
class nsIDNSListener;
class nsICancelable;
class nsDNSLookup;
class nsDNSService : public nsIDNSService,
public nsIRunnable
class nsDNSService : public nsIDNSService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
// nsDNSService methods:
nsDNSService();
@ -48,11 +55,24 @@ public:
NS_DECL_NSIDNSSERVICE
protected:
// nsDNSLookup cache? - list of nsDNSLookups
friend class nsDNSLookup;
friend pascal void nsDnsServiceNotifierRoutine(void * contextPtr, OTEventCode code, OTResult result, void * cookie);
nsIThread * mThread;
PRBool mThreadRunning;
// nsDNSLookup cache? - list of nsDNSLookups, hash table (nsHashTable, nsStringKey)
// list of nsDNSLookups in order of expiration (PRCList?)
#if defined(XP_MAC)
InetSvcRef mServiceRef;
InetSvcRef mServiceRef;
QHdr mCompletionQueue;
#if TARGET_CARBON
OTClientContextPtr mClientContext;
OTNotifyUPP nsDnsServiceNotifierRoutineUPP;
#endif /* TARGET_CARBON */
#elif defined(XP_UNIX)
//XXX - to be defined

Двоичные данные
netwerk/macbuild/netwerk.mcp

Двоичный файл не отображается.