5 uses binipstuff,classes,lcore;
\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 : string;familyhint:integer;var error : integer) : tbiniplist;
\r
13 function winreverselookup(ip:tbinip;var error:integer):string;
\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
25 freewhendone : boolean;
\r
28 procedure execute; override;
\r
30 onrequestdone:tsocketevent;
\r
32 iplist : tbiniplist;
\r
34 procedure forwardlookup(name:string);
\r
35 procedure reverselookup(ip:tbinip);
\r
36 destructor destroy; override;
\r
39 property reverse : boolean read freverse;
\r
45 lsocket,pgtypes,sysutils,winsock,windows,messages;
\r
48 //taddrinfo = record; //forward declaration
\r
49 paddrinfo = ^taddrinfo;
\r
50 taddrinfo = packed record
\r
52 ai_family : longint;
\r
53 ai_socktype : longint;
\r
54 ai_protocol : longint;
\r
55 ai_addrlen : taddrint;
\r
56 ai_canonname : pchar;
\r
57 ai_addr : pinetsockaddrv;
\r
58 ai_next : paddrinfo;
\r
60 ppaddrinfo = ^paddrinfo;
\r
61 tgetaddrinfo = function(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r
62 tfreeaddrinfo = procedure(ai : paddrinfo); stdcall;
\r
63 tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pchar;hostlen : longint;serv:pchar;servlen:longint;flags:longint) : longint;stdcall;
\r
65 getaddrinfo : tgetaddrinfo;
\r
66 freeaddrinfo : tfreeaddrinfo;
\r
67 getnameinfo : tgetnameinfo;
\r
68 procedure v4onlyfreeaddrinfo(ai : paddrinfo); stdcall;
\r
72 while assigned(ai) do begin
\r
73 freemem(ai.ai_addr);
\r
81 plongint = ^longint;
\r
82 pplongint = ^plongint;
\r
84 function v4onlygetaddrinfo(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r
86 output,prev,first : paddrinfo;
\r
90 if hints.ai_family <> af_inet6 then begin
\r
94 hostent := gethostbyname(nodename);
\r
95 if hostent = nil then begin
\r
96 result := wsagetlasterror;
\r
97 v4onlyfreeaddrinfo(output);
\r
100 addrlist := pointer(hostent.h_addr_list);
\r
102 //ipint := pplongint(hostent.h_addr_list)^^;
\r
106 if not assigned(addrlist^) then break;
\r
108 getmem(output,sizeof(taddrinfo));
\r
109 if assigned(prev) then prev.ai_next := output;
\r
110 getmem(output.ai_addr,sizeof(tinetsockaddr));
\r
111 if servname <> nil then output.ai_addr.InAddr.port := htons(strtoint(servname)) else output.ai_addr.InAddr.port := 0;
\r
112 output.ai_addr.InAddr.addr := longint(addrlist^^);
\r
113 inc(integer(addrlist),4);
\r
114 output.ai_flags := 0;
\r
115 output.ai_family := af_inet;
\r
116 output.ai_socktype := 0;
\r
117 output.ai_protocol := 0;
\r
118 output.ai_addrlen := sizeof(tinetsockaddr);
\r
119 output.ai_canonname := nil;
\r
120 output.ai_next := nil;
\r
122 if not assigned(first) then first := output;
\r
126 result := WSANO_RECOVERY;
\r
130 function min(a,b : integer):integer;
\r
132 if a<b then result := a else result := b;
\r
135 function v4onlygetnameinfo(sa:Pinetsockaddrv;salen : longint; host:pchar;hostlen : longint;serv:pchar;servlen:longint;flags:longint) : longint;stdcall;
\r
137 hostent : phostent;
\r
138 bytestocopy : integer;
\r
140 if sa.InAddr.family = af_inet then begin
\r
142 hostent := gethostbyaddr(@(sa.inaddr.addr),4,AF_INET);
\r
143 if hostent = nil then begin
\r
144 result := wsagetlasterror;
\r
147 bytestocopy := min(strlen(hostent.h_name)+1,hostlen);
\r
148 move((hostent.h_name)^,host^,bytestocopy);
\r
152 result := WSANO_RECOVERY;
\r
157 procedure populateprocvars;
\r
159 libraryhandle : hmodule;
\r
164 if assigned(getaddrinfo) then exit; //procvars already populated
\r
165 for i := 0 to 1 do begin
\r
166 if i=0 then dllname := 'Ws2_32.dll' else dllname := 'Wship6.dll';
\r
167 libraryhandle := LoadLibrary(pchar(dllname));
\r
168 getaddrinfo := getprocaddress(libraryhandle,'getaddrinfo');
\r
169 freeaddrinfo := getprocaddress(libraryhandle,'freeaddrinfo');
\r
170 getnameinfo := getprocaddress(libraryhandle,'getnameinfo');
\r
171 if assigned(getaddrinfo) and assigned(freeaddrinfo) and assigned(getnameinfo) then begin
\r
172 //writeln('found getaddrinfo and freeaddrinfo in'+dllname);
\r
177 //writeln('could not find getaddrinfo and freeaddrinfo, falling back to ipv4 only lookup');
\r
178 getaddrinfo := v4onlygetaddrinfo;
\r
179 freeaddrinfo := v4onlyfreeaddrinfo;
\r
180 getnameinfo := v4onlygetnameinfo;
\r
184 function winforwardlookuplist(name : string;familyhint:integer;var error : integer) : tbiniplist;
\r
187 res0,res : paddrinfo;
\r
188 getaddrinforesult : integer;
\r
193 hints.ai_flags := 0;
\r
194 hints.ai_family := familyhint;
\r
195 hints.ai_socktype := 0;
\r
196 hints.ai_protocol := 0;
\r
197 hints.ai_addrlen := 0;
\r
198 hints.ai_canonname := nil;
\r
199 hints.ai_addr := nil;
\r
200 hints.ai_next := nil;
\r
201 getaddrinforesult := getaddrinfo(pchar(name),'1',@hints,@res);
\r
203 result := biniplist_new;
\r
204 if getaddrinforesult = 0 then begin
\r
206 while assigned(res) do begin
\r
207 if res.ai_family = af_inet then begin
\r
208 biniptemp.family := af_inet;
\r
209 biniptemp.ip := res.ai_addr.InAddr.addr;
\r
210 biniplist_add(result,biniptemp);
\r
212 end else if res.ai_family = af_inet6 then begin
\r
213 biniptemp.family := af_inet6;
\r
214 biniptemp.ip6 := res.ai_addr.InAddr6.sin6_addr;
\r
215 biniplist_add(result,biniptemp);
\r
218 res := res.ai_next;
\r
220 freeaddrinfo(res0);
\r
224 if getaddrinforesult <> 0 then begin
\r
225 fillchar(result,0,sizeof(result));
\r
226 error := getaddrinforesult;
\r
230 function winreverselookup(ip:tbinip;var error : integer):string;
\r
232 sa : tinetsockaddrv;
\r
233 getnameinforesult : integer;
\r
236 if ip.family = AF_INET then begin
\r
237 sa.InAddr.family := AF_INET;
\r
238 sa.InAddr.port := 1;
\r
239 sa.InAddr.addr := ip.ip;
\r
240 end else {$ifdef ipv6}if ip.family = AF_INET6 then begin
\r
241 sa.InAddr6.sin6_family := AF_INET6;
\r
242 sa.InAddr6.sin6_port := 1;
\r
243 sa.InAddr6.sin6_addr := ip.ip6;
\r
244 end else{$endif} begin
\r
245 raise exception.create('unrecognised address family');
\r
248 setlength(result,1025);
\r
249 getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pchar(result),length(result),nil,0,0);
\r
250 if getnameinforesult <> 0 then begin
\r
251 error := getnameinforesult;
\r
255 if pos(#0,result) >= 0 then begin
\r
256 setlength(result,pos(#0,result)-1);
\r
263 function MyWindowProc(
\r
267 alParam : LPARAM): Integer; stdcall;
\r
269 dwas : tdnswinasync;
\r
271 if (ahwnd=hwnddnswin) and (aumsg=wm_user) then begin
\r
272 Dwas := tdnswinasync(alparam);
\r
273 if assigned (dwas.onrequestdone) then dwas.onrequestdone(dwas,awparam);
\r
274 dwas.hadevent := true;
\r
275 if dwas.freewhendone then dwas.free;
\r
277 //not passing unknown messages on to defwindowproc will cause window
\r
278 //creation to fail! --plugwash
\r
279 Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r
283 procedure tdnswinasync.forwardlookup(name:string);
\r
289 procedure tdnswinasync.reverselookup(ip:tbinip);
\r
291 iplist := biniplist_new;
\r
292 biniplist_add(iplist,ip);
\r
297 procedure tdnswinasync.execute;
\r
303 if reverse then begin
\r
304 name := winreverselookup(biniplist_get(iplist,0),error);
\r
306 iplist := winforwardlookuplist(name,0,error);
\r
309 postmessage(hwnddnswin,wm_user,error,taddrint(self));
\r
312 destructor tdnswinasync.destroy;
\r
317 procedure tdnswinasync.release;
\r
319 if hadevent then destroy else begin
\r
320 onrequestdone := nil;
\r
321 freewhendone := true;
\r
325 constructor tdnswinasync.create;
\r
327 inherited create(true);
\r
331 MyWindowClass : TWndClass = (style : 0;
\r
332 lpfnWndProc : @MyWindowProc;
\r
339 lpszMenuName : nil;
\r
340 lpszClassName : 'dnswinClass');
\r
343 if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r
344 //writeln('about to create lcore handle, hinstance=',hinstance);
\r
345 hwnddnswin := CreateWindowEx(WS_EX_TOOLWINDOW,
\r
346 MyWindowClass.lpszClassName,
\r
347 '', { Window name }
\r
348 WS_POPUP, { Window Style }
\r
350 0, 0, { Width, Height }
\r
353 HInstance, { hInstance }
\r
354 nil); { CreateParam }
\r
355 //writeln('dnswin hwnd is ',hwnddnswin);
\r
356 //writeln('last error is ',GetLastError);
\r