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
44 { zipplet: moved pgtypes to interface because it's needed for the string definitions }
\r
45 lsocket,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 : pansichar;
\r
57 ai_addr : pinetsockaddrv;
\r
58 ai_next : paddrinfo;
\r
60 ppaddrinfo = ^paddrinfo;
\r
61 tgetaddrinfo = function(nodename : pansichar; servname : pansichar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r
62 tfreeaddrinfo = procedure(ai : paddrinfo); stdcall;
\r
63 tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pansichar;hostlen : longint;serv:pansichar;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 : pansichar; servname : pansichar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r
86 output,prev,first : paddrinfo;
\r
91 if hints.ai_family <> af_inet6 then begin
\r
95 hostent := gethostbyname(nodename);
\r
96 if hostent = nil then begin
\r
97 result := wsagetlasterror;
\r
98 v4onlyfreeaddrinfo(output);
\r
101 addrlist := pointer(hostent.h_addr_list);
\r
103 //ipint := pplongint(hostent.h_addr_list)^^;
\r
107 if not assigned(addrlist^) then break;
\r
109 getmem(output,sizeof(taddrinfo));
\r
110 if assigned(prev) then prev.ai_next := output;
\r
111 getmem(output.ai_addr,sizeof(tinetsockaddr));
\r
112 if servname <> nil then output.ai_addr.InAddr.port := htons(strtoint(servname)) else output.ai_addr.InAddr.port := 0;
\r
113 output.ai_addr.InAddr.addr := longint(addrlist^^);
\r
114 inc(integer(addrlist),4);
\r
115 output.ai_flags := 0;
\r
116 output.ai_family := af_inet;
\r
117 output.ai_socktype := 0;
\r
118 output.ai_protocol := 0;
\r
119 output.ai_addrlen := sizeof(tinetsockaddr);
\r
120 output.ai_canonname := nil;
\r
121 output.ai_next := nil;
\r
123 if not assigned(first) then first := output;
\r
127 result := WSANO_RECOVERY;
\r
131 function min(a,b : integer):integer;
\r
133 if a<b then result := a else result := b;
\r
136 function v4onlygetnameinfo(sa:Pinetsockaddrv;salen : longint; host:pansichar;hostlen : longint;serv:pansichar;servlen:longint;flags:longint) : longint;stdcall;
\r
138 hostent : phostent;
\r
139 bytestocopy : integer;
\r
141 if sa.InAddr.family = af_inet then begin
\r
143 hostent := gethostbyaddr(@(sa.inaddr.addr),4,AF_INET);
\r
144 if hostent = nil then begin
\r
145 result := wsagetlasterror;
\r
148 bytestocopy := min(strlen(hostent.h_name)+1,hostlen);
\r
149 move((hostent.h_name)^,host^,bytestocopy);
\r
153 result := WSANO_RECOVERY;
\r
158 procedure populateprocvars;
\r
160 libraryhandle : hmodule;
\r
162 dllname : ansistring;
\r
165 if assigned(getaddrinfo) then exit; //procvars already populated
\r
166 for i := 0 to 1 do begin
\r
167 if i=0 then dllname := 'Ws2_32.dll' else dllname := 'Wship6.dll';
\r
168 libraryhandle := LoadLibraryA(pansichar(dllname));
\r
169 getaddrinfo := getprocaddress(libraryhandle,'getaddrinfo');
\r
170 freeaddrinfo := getprocaddress(libraryhandle,'freeaddrinfo');
\r
171 getnameinfo := getprocaddress(libraryhandle,'getnameinfo');
\r
172 if assigned(getaddrinfo) and assigned(freeaddrinfo) and assigned(getnameinfo) then begin
\r
173 //writeln('found getaddrinfo and freeaddrinfo in'+dllname);
\r
178 //writeln('could not find getaddrinfo and freeaddrinfo, falling back to ipv4 only lookup');
\r
179 getaddrinfo := v4onlygetaddrinfo;
\r
180 freeaddrinfo := v4onlyfreeaddrinfo;
\r
181 getnameinfo := v4onlygetnameinfo;
\r
185 function winforwardlookuplist(name : thostname;familyhint:integer;var error : integer) : tbiniplist;
\r
188 res0,res : paddrinfo;
\r
189 getaddrinforesult : integer;
\r
194 hints.ai_flags := 0;
\r
195 hints.ai_family := familyhint;
\r
196 hints.ai_socktype := 0;
\r
197 hints.ai_protocol := 0;
\r
198 hints.ai_addrlen := 0;
\r
199 hints.ai_canonname := nil;
\r
200 hints.ai_addr := nil;
\r
201 hints.ai_next := nil;
\r
202 getaddrinforesult := getaddrinfo(pansichar(name),'1',@hints,@res);
\r
204 result := biniplist_new;
\r
205 if getaddrinforesult = 0 then begin
\r
207 while assigned(res) do begin
\r
208 if res.ai_family = af_inet then begin
\r
209 biniptemp.family := af_inet;
\r
210 biniptemp.ip := res.ai_addr.InAddr.addr;
\r
211 biniplist_add(result,biniptemp);
\r
213 end else if res.ai_family = af_inet6 then begin
\r
214 biniptemp.family := af_inet6;
\r
215 biniptemp.ip6 := res.ai_addr.InAddr6.sin6_addr;
\r
216 biniplist_add(result,biniptemp);
\r
219 res := res.ai_next;
\r
221 freeaddrinfo(res0);
\r
225 if getaddrinforesult <> 0 then begin
\r
226 fillchar(result,0,sizeof(result));
\r
227 error := getaddrinforesult;
\r
231 function winreverselookup(ip:tbinip;var error : integer):thostname;
\r
233 sa : tinetsockaddrv;
\r
234 getnameinforesult : integer;
\r
237 makeinaddrv(ip,'1',sa);
\r
239 setlength(result,1025);
\r
240 getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pansichar(result),length(result),nil,0,0);
\r
241 if getnameinforesult <> 0 then begin
\r
242 error := getnameinforesult;
\r
246 if pos(#0,result) >= 0 then begin
\r
247 setlength(result,pos(#0,result)-1);
\r
254 function MyWindowProc(
\r
258 alParam : LPARAM): Integer; stdcall;
\r
260 dwas : tdnswinasync;
\r
262 if (ahwnd=hwnddnswin) and (aumsg=wm_user) then begin
\r
263 Dwas := tdnswinasync(alparam);
\r
264 if assigned (dwas.onrequestdone) then dwas.onrequestdone(dwas,awparam);
\r
265 dwas.hadevent := true;
\r
266 if dwas.freewhendone then dwas.free;
\r
267 result := 0; {added returning 0 when handling --beware}
\r
269 //not passing unknown messages on to defwindowproc will cause window
\r
270 //creation to fail! --plugwash
\r
271 Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r
275 procedure tdnswinasync.forwardlookup(name:thostname);
\r
281 procedure tdnswinasync.reverselookup(ip:tbinip);
\r
283 iplist := biniplist_new;
\r
284 biniplist_add(iplist,ip);
\r
289 procedure tdnswinasync.execute;
\r
295 if reverse then begin
\r
296 name := winreverselookup(biniplist_get(iplist,0),error);
\r
298 iplist := winforwardlookuplist(name,0,error);
\r
301 postmessage(hwnddnswin,wm_user,error,taddrint(self));
\r
304 destructor tdnswinasync.destroy;
\r
309 procedure tdnswinasync.release;
\r
311 if hadevent then destroy else begin
\r
312 onrequestdone := nil;
\r
313 freewhendone := true;
\r
317 constructor tdnswinasync.create;
\r
319 inherited create(true);
\r
323 MyWindowClass : TWndClass = (style : 0;
\r
324 lpfnWndProc : @MyWindowProc;
\r
331 lpszMenuName : nil;
\r
332 lpszClassName : 'dnswinClass');
\r
335 if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r
336 //writeln('about to create lcore handle, hinstance=',hinstance);
\r
337 hwnddnswin := CreateWindowEx(WS_EX_TOOLWINDOW,
\r
338 MyWindowClass.lpszClassName,
\r
339 '', { Window name }
\r
340 WS_POPUP, { Window Style }
\r
342 0, 0, { Width, Height }
\r
345 HInstance, { hInstance }
\r
346 nil); { CreateParam }
\r
347 //writeln('dnswin hwnd is ',hwnddnswin);
\r
348 //writeln('last error is ',GetLastError);
\r