/* 

macdns.c 

Implements asynchronous DNS lookups on the Mac 

*/

#include "macdns.h"

/* prototypes */
void AsyncTimeoutStart(unsigned long delay);
Boolean AsyncTimeoutExpired();
static pascal u_long DNRCallBackProc(NMMessageHandler h, u_int wMsg, u_long wParam, u_long lParam);

/*#define BFSZ 1000*/

/* globals */
NMMessageHandler DnrHandler = NM_INVALID_HANDLER;
NMMessageHandler AsyncHandler = NM_INVALID_HANDLER;
long DnrTaskHandle;
long AsyncTimeout = TCP_DEFAULT_TIMEOUT;
unsigned long AsyncEndTicks = 0;
Boolean notifyDNR = false;
OSErr notifyDNRResult = noErr;

/*
int main(void)
{
 	struct sockaddr_in xsin;
 	struct hostent* myhost;
	char HostName[BFSZ];
	char addr[BFSZ];
	long addr2;
	char* hosts[]={"ball.netwin.co.nz","port.netwin.co.nz","netwin.co.nz","trek.netwin.co.nz","161.29.2.5","uni.massey.ac.nz"};
    int num_hosts=6;
    int i;
    
	if (init_windows_sockets()!=NULL)
	{
		for(i=0;i<num_hosts;i++)
		{ 
		    strcpy(HostName,hosts[i]);
	        if ((myhost = _gethostbyname(HostName))==NULL)
	            printf("DNS Lookup failed\n");
	        else
	        {
	            memset(&xsin,0,sizeof(struct sockaddr_in));
                memcpy(&xsin.sin_addr,myhost->h_addr_list[0],myhost->h_length);
	            strcpy(addr,inet_ntoa(xsin.sin_addr));
	            printf("IP Number : '%s'\n",addr);
	            addr2 = inet_addr(addr);
	            if ((myhost = _gethostbyaddr((char *)&addr2,4,PF_INET))==NULL)
	                printf("Reverse DNS Lookup failed\n");
	            else
	                printf("Reverse DNS Lookup of '%s' gave '%s'\n",addr,myhost->h_name);   
	        }
	    }
	    WSACleanup();
	}
	else
	{
	    printf("DNS: Couldn't initialise windows sockets API!\n");
        return NULL;
    }
    return 1;
}
*/

struct hostent* macgethostbyaddr(const char *addr, int len, int type)
{
	Boolean TimedOut = false;
	static char DnrBuffer[MAXGETHOSTSTRUCT];
    HOSTENT* pDnrBuffer = (HOSTENT*) DnrBuffer;
   	    
	if (NMInitializeMessages()!=TRUE)
	{
        dmsg("DNS: Could not initialise Message API\n");
        return NULL;
	}
	dmsg("DNS: Attempting Asynchronous Reverse DNS lookup '%x'\n",addr);
	TimedOut = false;
	notifyDNR = false;
	AsyncTimeoutStart(TCP_DEFAULT_TIMEOUT);
	DnrHandler = NMCreateMessageHandler(NewNMMessageCallbackProc(DNRCallBackProc), NULL, 0 );
	if ((DnrHandler == NULL) || (DnrHandler == NM_INVALID_HANDLER))
	{
	    dmsg("DNS: Could not create message handler!\n");
	    return NULL;
	}
	DnrTaskHandle = WSAAsyncGetHostByAddr(DnrHandler, (u_int)DNR_DONE, addr, len, type, DnrBuffer, MAXGETHOSTSTRUCT);
	if (DnrTaskHandle == 0)
	{
	    dmsg("DNS: WSAAsyncGetHostByAddr call failed!\n");
		return NULL;
	}
	for (;;)
	{
	    if (AsyncTimeoutExpired())
	    {
	        TimedOut = true;
	        break;
	    }
	    CheckEvents();
	    NMIdle();
	    if (notifyDNR)
	       break;
	}
    if (notifyDNRResult!=0)
    {
        dmsg("DNS: DNR RESULT *** '%d'\n",notifyDNRResult);
        dmsg("DNS: Reverse DNS lookup didn't succeed, probably invalid IP address (%x)\n",addr);
        return NULL;
    }
    if (TimedOut == true)
    {
        dmsg("DNS: Reverse DNS Lookup timed out!\n");
        return NULL;
    }
    if (NMDestroyMessageHandler(DnrHandler, 0)==false)
    {
        dmsg("DNS: Could not destroy message handler!\n");
        return NULL;
    }
    return pDnrBuffer;
}

struct hostent* macgethostbyname(const char *HostName)
{
	Boolean TimedOut = false;
	static char DnrBuffer[MAXGETHOSTSTRUCT];
    HOSTENT* pDnrBuffer = (HOSTENT*) DnrBuffer;
   	    
	if (NMInitializeMessages()!=TRUE)
	{
        dmsg("DNS: Could not initialise Message API\n");
        return NULL;
	}
	dmsg("DNS: Attempting Asynchronous DNS lookup '%s'\n",HostName);
	TimedOut = false;
	notifyDNR = false;
	AsyncTimeoutStart(TCP_DEFAULT_TIMEOUT);
	DnrHandler = NMCreateMessageHandler(NewNMMessageCallbackProc(DNRCallBackProc), NULL, 0 );
	if ((DnrHandler == NULL) || (DnrHandler == NM_INVALID_HANDLER))
	{
	    dmsg("DNS: Could not create message handler!\n");
	    return NULL;
	}
	DnrTaskHandle = WSAAsyncGetHostByName(DnrHandler, (u_int)DNR_DONE, HostName, DnrBuffer, MAXGETHOSTSTRUCT);
	if (DnrTaskHandle == 0)
	{
	    dmsg("DNS: WSAAsyncGetHostByName call failed!\n");
		return NULL;
	}
	for (;;)
	{
	    if (AsyncTimeoutExpired())
	    {
	        TimedOut = true;
	        break;
	    }
	    CheckEvents();
	    NMIdle();
	    if (notifyDNR)
	       break;
	}
    if (notifyDNRResult!=0)
    {
        /*dmsg("DNS: DNR RESULT *** '%d'\n",notifyDNRResult);*/
        dmsg("DNS: DNS lookup didn't succeed, probably invalid domain (%s)\n",HostName);
        return NULL;
    }
    if (TimedOut == true)
    {
        dmsg("DNS: DNS Lookup timed out!\n");
        return NULL;
    }
    if (NMDestroyMessageHandler(DnrHandler, 0)==false)
    {
        dmsg("DNS: Could not destroy message handler!\n");
        return NULL;
    }
    return pDnrBuffer;
}

static pascal u_long DNRCallBackProc(NMMessageHandler h, u_int wMsg, u_long wParam, u_long lParam)
{
	long			errCode		= WSAGETASYNCERROR(lParam);
    switch (wMsg)
    {
       case DNR_DONE:
          notifyDNRResult	= errCode;
	      notifyDNR			= TRUE;
	      break;
	}
	return(0);
}

void AsyncTimeoutStart(unsigned long delay)
{
	if (AsyncTimeout != -1)
		AsyncEndTicks = TickCount() + delay;
}

Boolean AsyncTimeoutExpired()
{
	if (AsyncTimeout == -1)
		return(FALSE);
	else
		return(TickCount() > AsyncEndTicks);
}
