add linux syscall sys_getrandom to lcorernd
[lcore.git] / dnswin.pas
old mode 100755 (executable)
new mode 100644 (file)
index 7d986d1..5e85f70
@@ -1,13 +1,16 @@
 unit dnswin;\r
 \r
 interface\r
-uses binipstuff,classes,lcore;\r
+\r
+uses binipstuff,classes,lcore,pgtypes;\r
+\r
+{$include lcoreconfig.inc}\r
 \r
 //on failure a null string or zeroed out binip will be retuned and error will be\r
 //set to a windows error code (error will be left untouched under non error\r
 //conditions).\r
-function winforwardlookup(name : string;ipv6preffered : boolean;var error:integer) : tbinip;\r
-function winreverselookup(ip:tbinip;var error:integer):string;\r
+function winforwardlookuplist(name : thostname;familyhint:integer;var error : integer) : tbiniplist;\r
+function winreverselookup(ip:tbinip;var error:integer):thostname;\r
 \r
 \r
 type\r
@@ -17,19 +20,17 @@ type
   //release should only be called from the main thread\r
   tdnswinasync=class(tthread)\r
   private\r
-    ipv6preffered : boolean;\r
     freverse : boolean;\r
-    error : integer;\r
     freewhendone : boolean;\r
     hadevent : boolean;\r
   protected\r
     procedure execute; override;\r
   public\r
     onrequestdone:tsocketevent;\r
-    name : string;\r
-    ip : tbinip;\r
+    name : thostname;\r
+    iplist : tbiniplist;\r
 \r
-    procedure forwardlookup(name:string;ipv6preffered:boolean);\r
+    procedure forwardlookup(name:thostname);\r
     procedure reverselookup(ip:tbinip);\r
     destructor destroy; override;\r
     procedure release;\r
@@ -38,9 +39,12 @@ type
 \r
   end;\r
 \r
+procedure init;\r
+\r
 implementation\r
 uses\r
-  lsocket,pgtypes,sysutils,winsock,windows,messages;\r
+  // zipplet: moved pgtypes to interface because it's needed for the string definitions\r
+  lsocket,sysutils,winsock,windows,messages;\r
 \r
 type\r
   //taddrinfo = record; //forward declaration\r
@@ -51,55 +55,76 @@ type
     ai_socktype : longint;\r
     ai_protocol : longint;\r
     ai_addrlen : taddrint;\r
-    ai_canonname : pchar;\r
+    ai_canonname : pansichar;\r
     ai_addr : pinetsockaddrv;\r
     ai_next : paddrinfo;\r
   end;\r
   ppaddrinfo = ^paddrinfo;\r
-  tgetaddrinfo = function(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;\r
+  tgetaddrinfo = function(nodename : pansichar; servname : pansichar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;\r
   tfreeaddrinfo = procedure(ai : paddrinfo); stdcall;\r
-  tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pchar;hostlen : longint;serv:pchar;servlen:longint;flags:longint) : longint;stdcall;\r
+  tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pansichar;hostlen : longint;serv:pansichar;servlen:longint;flags:longint) : longint;stdcall;\r
 var\r
   getaddrinfo : tgetaddrinfo;\r
   freeaddrinfo : tfreeaddrinfo;\r
   getnameinfo : tgetnameinfo;\r
 procedure v4onlyfreeaddrinfo(ai : paddrinfo); stdcall;\r
+var\r
+  next:paddrinfo;\r
 begin\r
-  freemem(ai.ai_addr);\r
-  freemem(ai);\r
+  while assigned(ai) do begin\r
+    freemem(ai.ai_addr);\r
+    next := ai.ai_next;\r
+    freemem(ai);\r
+    ai := next;\r
+  end;\r
 end;\r
 \r
 type\r
   plongint = ^longint;\r
   pplongint = ^plongint;\r
 \r
-function v4onlygetaddrinfo(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;\r
+function v4onlygetaddrinfo(nodename : pansichar; servname : pansichar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;\r
 var\r
-  output : paddrinfo;\r
+  output,prev,first : paddrinfo;\r
   hostent : phostent;\r
+  addrlist:^pointer;\r
 begin\r
-  if hints.ai_family = af_inet then begin\r
+  output := nil;\r
+  if hints.ai_family <> af_inet6 then begin\r
     result := 0;\r
-    getmem(output,sizeof(taddrinfo));\r
-    getmem(output.ai_addr,sizeof(tinetsockaddr));\r
-    output.ai_addr.InAddr.family := af_inet;\r
-    if servname <> nil then output.ai_addr.InAddr.port := htons(strtoint(servname)) else output.ai_addr.InAddr.port := 0;\r
+\r
+\r
     hostent := gethostbyname(nodename);\r
     if hostent = nil then begin\r
       result := wsagetlasterror;\r
       v4onlyfreeaddrinfo(output);\r
       exit;\r
     end;\r
-    output.ai_addr.InAddr.addr := pplongint(hostent.h_addr_list)^^;\r
-    output.ai_flags := 0;\r
-    output.ai_family := af_inet;\r
-    output.ai_socktype := 0;\r
-    output.ai_protocol := 0;\r
-    output.ai_addrlen := sizeof(tinetsockaddr);\r
-    output.ai_canonname := nil;\r
-    output.ai_next := nil;\r
-\r
-    res^ := output;\r
+    addrlist := pointer(hostent.h_addr_list);\r
+\r
+    //ipint := pplongint(hostent.h_addr_list)^^;\r
+    prev := nil;\r
+    first := nil;\r
+    repeat\r
+      if not assigned(addrlist^) then break;\r
+\r
+      getmem(output,sizeof(taddrinfo));\r
+      if assigned(prev) then prev.ai_next := output;\r
+      getmem(output.ai_addr,sizeof(tlinetsockaddr4));\r
+      if servname <> nil then output.ai_addr.InAddr.port := htons(strtoint(servname)) else output.ai_addr.InAddr.port := 0;\r
+      output.ai_addr.InAddr.addr := longint(addrlist^^);\r
+      inc(taddrint(addrlist),4);\r
+      output.ai_flags := 0;\r
+      output.ai_family := af_inet;\r
+      output.ai_socktype := 0;\r
+      output.ai_protocol := 0;\r
+      output.ai_addrlen := sizeof(tlinetsockaddr4);\r
+      output.ai_canonname := nil;\r
+      output.ai_next := nil;\r
+      prev := output;\r
+      if not assigned(first) then first := output;\r
+    until false;\r
+    res^ := first;\r
   end else begin\r
     result := WSANO_RECOVERY;\r
   end;\r
@@ -110,7 +135,7 @@ begin
   if a<b then result := a else result := b;\r
 end;\r
 \r
-function v4onlygetnameinfo(sa:Pinetsockaddrv;salen : longint; host:pchar;hostlen : longint;serv:pchar;servlen:longint;flags:longint) : longint;stdcall;\r
+function v4onlygetnameinfo(sa:Pinetsockaddrv;salen : longint; host:pansichar;hostlen : longint;serv:pansichar;servlen:longint;flags:longint) : longint;stdcall;\r
 var\r
   hostent : phostent;\r
   bytestocopy : integer;\r
@@ -136,13 +161,13 @@ procedure populateprocvars;
 var\r
   libraryhandle : hmodule;\r
   i : integer;\r
-  dllname : string;\r
+  dllname : ansistring;\r
 \r
 begin\r
   if assigned(getaddrinfo) then exit; //procvars already populated\r
   for i := 0 to 1 do begin\r
     if i=0 then dllname := 'Ws2_32.dll' else dllname := 'Wship6.dll';\r
-    libraryhandle := LoadLibrary(pchar(dllname));\r
+    libraryhandle := LoadLibraryA(pansichar(dllname));\r
     getaddrinfo := getprocaddress(libraryhandle,'getaddrinfo');\r
     freeaddrinfo := getprocaddress(libraryhandle,'freeaddrinfo');\r
     getnameinfo := getprocaddress(libraryhandle,'getnameinfo');\r
@@ -159,70 +184,62 @@ begin
 end;\r
 \r
 \r
-function winforwardlookup(name : string;ipv6preffered : boolean;var error : integer) : tbinip;\r
+function winforwardlookuplist(name : thostname;familyhint:integer;var error : integer) : tbiniplist;\r
 var\r
   hints: taddrinfo;\r
-  res : paddrinfo;\r
-  pass : boolean;\r
-  ipv6 : boolean;\r
+  res0,res : paddrinfo;\r
   getaddrinforesult : integer;\r
+  biniptemp:tbinip;\r
 begin\r
   populateprocvars;\r
 \r
-  for pass := false to true do begin\r
-    ipv6 := ipv6preffered xor pass;\r
-    hints.ai_flags := 0;\r
-    if ipv6 then begin\r
-      hints.ai_family := AF_INET6;\r
-    end else begin\r
-      hints.ai_family := AF_INET;\r
-    end;\r
-    hints.ai_socktype := 0;\r
-    hints.ai_protocol := 0;\r
-    hints.ai_addrlen := 0;\r
-    hints.ai_canonname := nil;\r
-    hints.ai_addr := nil;\r
-    hints.ai_next := nil;\r
-    getaddrinforesult := getaddrinfo(pchar(name),'1',@hints,@res);\r
-    if getaddrinforesult = 0 then begin\r
+  hints.ai_flags := 0;\r
+  hints.ai_family := familyhint;\r
+  hints.ai_socktype := 0;\r
+  hints.ai_protocol := 0;\r
+  hints.ai_addrlen := 0;\r
+  hints.ai_canonname := nil;\r
+  hints.ai_addr := nil;\r
+  hints.ai_next := nil;\r
+  getaddrinforesult := getaddrinfo(pansichar(name),'1',@hints,@res);\r
+  res0 := res;\r
+  result := biniplist_new;\r
+  if getaddrinforesult = 0 then begin\r
+\r
+    while assigned(res) do begin\r
       if res.ai_family = af_inet then begin\r
-        result.family := af_inet;\r
-        result.ip := res.ai_addr.InAddr.addr;\r
-      end else {$ifdef ipv6}if res.ai_family = af_inet6 then begin\r
-        result.family := af_inet6;\r
-        result.ip6 := res.ai_addr.InAddr6.sin6_addr;\r
-      end;{$endif};\r
-\r
-      freeaddrinfo(res);\r
-      exit;\r
+        biniptemp.family := af_inet;\r
+        biniptemp.ip := res.ai_addr.InAddr.addr;\r
+        biniplist_add(result,biniptemp);\r
+      {$ifdef ipv6}\r
+      end else if res.ai_family = af_inet6 then begin\r
+        biniptemp.family := af_inet6;\r
+        biniptemp.ip6 := res.ai_addr.InAddr6.sin6_addr;\r
+        biniplist_add(result,biniptemp);\r
+      {$endif}\r
+      end;\r
+      res := res.ai_next;\r
     end;\r
+    freeaddrinfo(res0);\r
+    exit;\r
   end;\r
+\r
   if getaddrinforesult <> 0 then begin\r
     fillchar(result,0,sizeof(result));\r
     error := getaddrinforesult;\r
   end;\r
 end;\r
 \r
-function winreverselookup(ip:tbinip;var error : integer):string;\r
+function winreverselookup(ip:tbinip;var error : integer):thostname;\r
 var\r
   sa : tinetsockaddrv;\r
   getnameinforesult : integer;\r
 begin\r
 \r
-  if ip.family = AF_INET then begin\r
-    sa.InAddr.family := AF_INET;\r
-    sa.InAddr.port := 1;\r
-    sa.InAddr.addr := ip.ip;\r
-  end else {$ifdef ipv6}if ip.family = AF_INET6 then begin\r
-    sa.InAddr6.sin6_family  := AF_INET6;\r
-    sa.InAddr6.sin6_port := 1;\r
-    sa.InAddr6.sin6_addr := ip.ip6;\r
-  end else{$endif} begin\r
-    raise exception.create('unrecognised address family');\r
-  end;\r
+  makeinaddrv(ip,'1',sa);\r
   populateprocvars;\r
   setlength(result,1025);\r
-  getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pchar(result),length(result),nil,0,0);\r
+  getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pansichar(result),length(result),nil,0,0);\r
   if getnameinforesult <> 0 then begin\r
     error := getnameinforesult;\r
     result := '';\r
@@ -249,6 +266,7 @@ begin
     if assigned (dwas.onrequestdone) then dwas.onrequestdone(dwas,awparam);\r
     dwas.hadevent := true;\r
     if dwas.freewhendone then dwas.free;\r
+    result := 0; {added returning 0 when handling --beware}\r
   end else begin\r
     //not passing unknown messages on to defwindowproc will cause window\r
     //creation to fail! --plugwash\r
@@ -256,35 +274,36 @@ begin
   end;\r
 end;\r
 \r
-procedure tdnswinasync.forwardlookup(name:string;ipv6preffered:boolean);\r
+procedure tdnswinasync.forwardlookup(name:thostname);\r
 begin\r
   self.name := name;\r
-  self.ipv6preffered := ipv6preffered;\r
   freverse := false;\r
   resume;\r
 end;\r
 procedure tdnswinasync.reverselookup(ip:tbinip);\r
 begin\r
-  self.ip := ip;\r
+  iplist := biniplist_new;\r
+  biniplist_add(iplist,ip);\r
   freverse := true;\r
   resume;\r
 end;\r
+\r
 procedure tdnswinasync.execute;\r
 var\r
   error : integer;\r
+\r
 begin\r
   error := 0;\r
   if reverse then begin\r
-    name := winreverselookup(ip,error);\r
+    name := winreverselookup(biniplist_get(iplist,0),error);\r
   end else begin\r
-    ip := winforwardlookup(name,ipv6preffered,error);\r
+    iplist := winforwardlookuplist(name,0,error);\r
 \r
   end;\r
-\r
   postmessage(hwnddnswin,wm_user,error,taddrint(self));\r
 end;\r
 \r
-destructor tdnswinasync.destroy; \r
+destructor tdnswinasync.destroy;\r
 begin\r
   WaitFor;\r
   inherited destroy;\r
@@ -313,6 +332,7 @@ var
                                  hbrBackground : 0;\r
                                  lpszMenuName  : nil;\r
                                  lpszClassName : 'dnswinClass');\r
+procedure init;\r
 begin\r
 \r
     if Windows.RegisterClass(MyWindowClass) = 0 then halt;\r
@@ -329,4 +349,7 @@ begin
                                nil);      { CreateParam   }\r
   //writeln('dnswin hwnd is ',hwnddnswin);\r
   //writeln('last error is ',GetLastError);\r
+end;\r
+\r
+\r
 end.\r