5 uses binipstuff,classes,lcore,pgtypes;
\r 
   7 {$include lcoreconfig.inc}
\r 
   9 //on failure a null string or zeroed out binip will be retuned and error will be
\r 
  10 //set to a windows error code (error will be left untouched under non error
\r 
  12 function winforwardlookuplist(name : thostname;familyhint:integer;var error : integer) : tbiniplist;
\r 
  13 function winreverselookup(ip:tbinip;var error:integer):thostname;
\r 
  17   //do not call destroy on a tdnswinasync instead call release and the
\r 
  18   //dnswinasync will be freed when appropriate. Calling destroy will block
\r 
  19   //the calling thread until the dns lookup completes.
\r 
  20   //release should only be called from the main thread
\r 
  21   tdnswinasync=class(tthread)
\r 
  24     freewhendone : boolean;
\r 
  27     procedure execute; override;
\r 
  29     onrequestdone:tsocketevent;
\r 
  31     iplist : tbiniplist;
\r 
  33     procedure forwardlookup(name:thostname);
\r 
  34     procedure reverselookup(ip:tbinip);
\r 
  35     destructor destroy; override;
\r 
  38     property reverse : boolean read freverse;
\r 
  46   // zipplet: moved pgtypes to interface because it's needed for the string definitions
\r 
  47   lsocket,sysutils,winsock,windows,messages;
\r 
  50   //taddrinfo = record; //forward declaration
\r 
  51   paddrinfo = ^taddrinfo;
\r 
  52   taddrinfo = packed record
\r 
  54     ai_family : longint;
\r 
  55     ai_socktype : longint;
\r 
  56     ai_protocol : longint;
\r 
  57     ai_addrlen : taddrint;
\r 
  58     ai_canonname : pansichar;
\r 
  59     ai_addr : pinetsockaddrv;
\r 
  60     ai_next : paddrinfo;
\r 
  62   ppaddrinfo = ^paddrinfo;
\r 
  63   tgetaddrinfo = function(nodename : pansichar; servname : pansichar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r 
  64   tfreeaddrinfo = procedure(ai : paddrinfo); stdcall;
\r 
  65   tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pansichar;hostlen : longint;serv:pansichar;servlen:longint;flags:longint) : longint;stdcall;
\r 
  67   getaddrinfo : tgetaddrinfo;
\r 
  68   freeaddrinfo : tfreeaddrinfo;
\r 
  69   getnameinfo : tgetnameinfo;
\r 
  70 procedure v4onlyfreeaddrinfo(ai : paddrinfo); stdcall;
\r 
  74   while assigned(ai) do begin
\r 
  75     freemem(ai.ai_addr);
\r 
  83   plongint = ^longint;
\r 
  84   pplongint = ^plongint;
\r 
  86 function v4onlygetaddrinfo(nodename : pansichar; servname : pansichar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r 
  88   output,prev,first : paddrinfo;
\r 
  93   if hints.ai_family <> af_inet6 then begin
\r 
  97     hostent := gethostbyname(nodename);
\r 
  98     if hostent = nil then begin
\r 
  99       result := wsagetlasterror;
\r 
 100       v4onlyfreeaddrinfo(output);
\r 
 103     addrlist := pointer(hostent.h_addr_list);
\r 
 105     //ipint := pplongint(hostent.h_addr_list)^^;
\r 
 109       if not assigned(addrlist^) then break;
\r 
 111       getmem(output,sizeof(taddrinfo));
\r 
 112       if assigned(prev) then prev.ai_next := output;
\r 
 113       getmem(output.ai_addr,sizeof(tlinetsockaddr4));
\r 
 114       if servname <> nil then output.ai_addr.InAddr.port := htons(strtoint(servname)) else output.ai_addr.InAddr.port := 0;
\r 
 115       output.ai_addr.InAddr.addr := longint(addrlist^^);
\r 
 116       inc(taddrint(addrlist),4);
\r 
 117       output.ai_flags := 0;
\r 
 118       output.ai_family := af_inet;
\r 
 119       output.ai_socktype := 0;
\r 
 120       output.ai_protocol := 0;
\r 
 121       output.ai_addrlen := sizeof(tlinetsockaddr4);
\r 
 122       output.ai_canonname := nil;
\r 
 123       output.ai_next := nil;
\r 
 125       if not assigned(first) then first := output;
\r 
 129     result := WSANO_RECOVERY;
\r 
 133 function min(a,b : integer):integer;
\r 
 135   if a<b then result := a else result := b;
\r 
 138 function v4onlygetnameinfo(sa:Pinetsockaddrv;salen : longint; host:pansichar;hostlen : longint;serv:pansichar;servlen:longint;flags:longint) : longint;stdcall;
\r 
 140   hostent : phostent;
\r 
 141   bytestocopy : integer;
\r 
 143   if sa.InAddr.family = af_inet then begin
\r 
 145     hostent := gethostbyaddr(@(sa.inaddr.addr),4,AF_INET);
\r 
 146     if hostent = nil then begin
\r 
 147       result := wsagetlasterror;
\r 
 150     bytestocopy := min(strlen(hostent.h_name)+1,hostlen);
\r 
 151     move((hostent.h_name)^,host^,bytestocopy);
\r 
 155     result := WSANO_RECOVERY;
\r 
 160 procedure populateprocvars;
\r 
 162   libraryhandle : hmodule;
\r 
 164   dllname : ansistring;
\r 
 167   if assigned(getaddrinfo) then exit; //procvars already populated
\r 
 168   for i := 0 to 1 do begin
\r 
 169     if i=0 then dllname := 'Ws2_32.dll' else dllname := 'Wship6.dll';
\r 
 170     libraryhandle := LoadLibraryA(pansichar(dllname));
\r 
 171     getaddrinfo := getprocaddress(libraryhandle,'getaddrinfo');
\r 
 172     freeaddrinfo := getprocaddress(libraryhandle,'freeaddrinfo');
\r 
 173     getnameinfo := getprocaddress(libraryhandle,'getnameinfo');
\r 
 174     if assigned(getaddrinfo) and assigned(freeaddrinfo) and assigned(getnameinfo) then begin
\r 
 175       //writeln('found getaddrinfo and freeaddrinfo in'+dllname);
\r 
 180   //writeln('could not find getaddrinfo and freeaddrinfo, falling back to ipv4 only lookup');
\r 
 181   getaddrinfo := v4onlygetaddrinfo;
\r 
 182   freeaddrinfo := v4onlyfreeaddrinfo;
\r 
 183   getnameinfo := v4onlygetnameinfo;
\r 
 187 function winforwardlookuplist(name : thostname;familyhint:integer;var error : integer) : tbiniplist;
\r 
 190   res0,res : paddrinfo;
\r 
 191   getaddrinforesult : integer;
\r 
 196   hints.ai_flags := 0;
\r 
 197   hints.ai_family := familyhint;
\r 
 198   hints.ai_socktype := 0;
\r 
 199   hints.ai_protocol := 0;
\r 
 200   hints.ai_addrlen := 0;
\r 
 201   hints.ai_canonname := nil;
\r 
 202   hints.ai_addr := nil;
\r 
 203   hints.ai_next := nil;
\r 
 204   getaddrinforesult := getaddrinfo(pansichar(name),'1',@hints,@res);
\r 
 206   result := biniplist_new;
\r 
 207   if getaddrinforesult = 0 then begin
\r 
 209     while assigned(res) do begin
\r 
 210       if res.ai_family = af_inet then begin
\r 
 211         biniptemp.family := af_inet;
\r 
 212         biniptemp.ip := res.ai_addr.InAddr.addr;
\r 
 213         biniplist_add(result,biniptemp);
\r 
 215       end else if res.ai_family = af_inet6 then begin
\r 
 216         biniptemp.family := af_inet6;
\r 
 217         biniptemp.ip6 := res.ai_addr.InAddr6.sin6_addr;
\r 
 218         biniplist_add(result,biniptemp);
\r 
 221       res := res.ai_next;
\r 
 223     freeaddrinfo(res0);
\r 
 227   if getaddrinforesult <> 0 then begin
\r 
 228     fillchar(result,0,sizeof(result));
\r 
 229     error := getaddrinforesult;
\r 
 233 function winreverselookup(ip:tbinip;var error : integer):thostname;
\r 
 235   sa : tinetsockaddrv;
\r 
 236   getnameinforesult : integer;
\r 
 239   makeinaddrv(ip,'1',sa);
\r 
 241   setlength(result,1025);
\r 
 242   getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pansichar(result),length(result),nil,0,0);
\r 
 243   if getnameinforesult <> 0 then begin
\r 
 244     error := getnameinforesult;
\r 
 248   if pos(#0,result) >= 0 then begin
\r 
 249     setlength(result,pos(#0,result)-1);
\r 
 256 function MyWindowProc(
\r 
 260     alParam : LPARAM): Integer; stdcall;
\r 
 262   dwas : tdnswinasync;
\r 
 264   if (ahwnd=hwnddnswin) and (aumsg=wm_user) then begin
\r 
 265     Dwas := tdnswinasync(alparam);
\r 
 266     if assigned (dwas.onrequestdone) then dwas.onrequestdone(dwas,awparam);
\r 
 267     dwas.hadevent := true;
\r 
 268     if dwas.freewhendone then dwas.free;
\r 
 269     result := 0; {added returning 0 when handling --beware}
\r 
 271     //not passing unknown messages on to defwindowproc will cause window
\r 
 272     //creation to fail! --plugwash
\r 
 273     Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r 
 277 procedure tdnswinasync.forwardlookup(name:thostname);
\r 
 283 procedure tdnswinasync.reverselookup(ip:tbinip);
\r 
 285   iplist := biniplist_new;
\r 
 286   biniplist_add(iplist,ip);
\r 
 291 procedure tdnswinasync.execute;
\r 
 297   if reverse then begin
\r 
 298     name := winreverselookup(biniplist_get(iplist,0),error);
\r 
 300     iplist := winforwardlookuplist(name,0,error);
\r 
 303   postmessage(hwnddnswin,wm_user,error,taddrint(self));
\r 
 306 destructor tdnswinasync.destroy;
\r 
 311 procedure tdnswinasync.release;
\r 
 313   if hadevent then destroy else begin
\r 
 314     onrequestdone := nil;
\r 
 315     freewhendone := true;
\r 
 319 constructor tdnswinasync.create;
\r 
 321   inherited create(true);
\r 
 325   MyWindowClass : TWndClass = (style         : 0;
\r 
 326                                  lpfnWndProc   : @MyWindowProc;
\r 
 333                                  lpszMenuName  : nil;
\r 
 334                                  lpszClassName : 'dnswinClass');
\r 
 338     if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r 
 339   //writeln('about to create lcore handle, hinstance=',hinstance);
\r 
 340   hwnddnswin := CreateWindowEx(WS_EX_TOOLWINDOW,
\r 
 341                                MyWindowClass.lpszClassName,
\r 
 342                                '',        { Window name   }
\r 
 343                                WS_POPUP,  { Window Style  }
\r 
 345                                0, 0,      { Width, Height }
\r 
 348                                HInstance, { hInstance     }
\r 
 349                                nil);      { CreateParam   }
\r 
 350   //writeln('dnswin hwnd is ',hwnddnswin);
\r 
 351   //writeln('last error is ',GetLastError);
\r