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
23 ipv6preffered : boolean;
\r
26 freewhendone : boolean;
\r
29 procedure execute; override;
\r
31 onrequestdone:tsocketevent;
\r
33 iplist : tbiniplist;
\r
35 procedure forwardlookup(name:string;ipv6preffered:boolean);
\r
36 procedure reverselookup(ip:tbinip);
\r
37 destructor destroy; override;
\r
40 property reverse : boolean read freverse;
\r
46 lsocket,pgtypes,sysutils,winsock,windows,messages;
\r
49 //taddrinfo = record; //forward declaration
\r
50 paddrinfo = ^taddrinfo;
\r
51 taddrinfo = packed record
\r
53 ai_family : longint;
\r
54 ai_socktype : longint;
\r
55 ai_protocol : longint;
\r
56 ai_addrlen : taddrint;
\r
57 ai_canonname : pchar;
\r
58 ai_addr : pinetsockaddrv;
\r
59 ai_next : paddrinfo;
\r
61 ppaddrinfo = ^paddrinfo;
\r
62 tgetaddrinfo = function(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r
63 tfreeaddrinfo = procedure(ai : paddrinfo); stdcall;
\r
64 tgetnameinfo = function(sa:Pinetsockaddrv;salen : longint; host:pchar;hostlen : longint;serv:pchar;servlen:longint;flags:longint) : longint;stdcall;
\r
66 getaddrinfo : tgetaddrinfo;
\r
67 freeaddrinfo : tfreeaddrinfo;
\r
68 getnameinfo : tgetnameinfo;
\r
69 procedure v4onlyfreeaddrinfo(ai : paddrinfo); stdcall;
\r
73 while assigned(ai) do begin
\r
74 freemem(ai.ai_addr);
\r
82 plongint = ^longint;
\r
83 pplongint = ^plongint;
\r
85 function v4onlygetaddrinfo(nodename : pchar; servname : pchar; hints : paddrinfo;res : ppaddrinfo) : longint; stdcall;
\r
87 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:pchar;hostlen : longint;serv:pchar;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
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 := LoadLibrary(pchar(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 : string;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(pchar(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):string;
\r
233 sa : tinetsockaddrv;
\r
234 getnameinforesult : integer;
\r
237 if ip.family = AF_INET then begin
\r
238 sa.InAddr.family := AF_INET;
\r
239 sa.InAddr.port := 1;
\r
240 sa.InAddr.addr := ip.ip;
\r
241 end else {$ifdef ipv6}if ip.family = AF_INET6 then begin
\r
242 sa.InAddr6.sin6_family := AF_INET6;
\r
243 sa.InAddr6.sin6_port := 1;
\r
244 sa.InAddr6.sin6_addr := ip.ip6;
\r
245 end else{$endif} begin
\r
246 raise exception.create('unrecognised address family');
\r
249 setlength(result,1025);
\r
250 getnameinforesult := getnameinfo(@sa,sizeof(tinetsockaddrv),pchar(result),length(result),nil,0,0);
\r
251 if getnameinforesult <> 0 then begin
\r
252 error := getnameinforesult;
\r
256 if pos(#0,result) >= 0 then begin
\r
257 setlength(result,pos(#0,result)-1);
\r
264 function MyWindowProc(
\r
268 alParam : LPARAM): Integer; stdcall;
\r
270 dwas : tdnswinasync;
\r
272 if (ahwnd=hwnddnswin) and (aumsg=wm_user) then begin
\r
273 Dwas := tdnswinasync(alparam);
\r
274 if assigned (dwas.onrequestdone) then dwas.onrequestdone(dwas,awparam);
\r
275 dwas.hadevent := true;
\r
276 if dwas.freewhendone then dwas.free;
\r
278 //not passing unknown messages on to defwindowproc will cause window
\r
279 //creation to fail! --plugwash
\r
280 Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r
284 procedure tdnswinasync.forwardlookup(name:string;ipv6preffered:boolean);
\r
287 self.ipv6preffered := ipv6preffered;
\r
291 procedure tdnswinasync.reverselookup(ip:tbinip);
\r
293 iplist := biniplist_new;
\r
294 biniplist_add(iplist,ip);
\r
299 procedure tdnswinasync.execute;
\r
305 if reverse then begin
\r
306 name := winreverselookup(biniplist_get(iplist,0),error);
\r
308 iplist := winforwardlookuplist(name,0,error);
\r
311 postmessage(hwnddnswin,wm_user,error,taddrint(self));
\r
314 destructor tdnswinasync.destroy;
\r
319 procedure tdnswinasync.release;
\r
321 if hadevent then destroy else begin
\r
322 onrequestdone := nil;
\r
323 freewhendone := true;
\r
327 constructor tdnswinasync.create;
\r
329 inherited create(true);
\r
333 MyWindowClass : TWndClass = (style : 0;
\r
334 lpfnWndProc : @MyWindowProc;
\r
341 lpszMenuName : nil;
\r
342 lpszClassName : 'dnswinClass');
\r
345 if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r
346 //writeln('about to create lcore handle, hinstance=',hinstance);
\r
347 hwnddnswin := CreateWindowEx(WS_EX_TOOLWINDOW,
\r
348 MyWindowClass.lpszClassName,
\r
349 '', { Window name }
\r
350 WS_POPUP, { Window Style }
\r
352 0, 0, { Width, Height }
\r
355 HInstance, { hInstance }
\r
356 nil); { CreateParam }
\r
357 //writeln('dnswin hwnd is ',hwnddnswin);
\r
358 //writeln('last error is ',GetLastError);
\r