1 { Copyright (C) 2005 Bas Steendijk and Peter Green
\r
2 For conditions of distribution and use, see copyright notice in zlib_license.txt
\r
3 which is included in the package
\r
4 ----------------------------------------------------------------------------- }
\r
6 //FIXME: this code only ever seems to use one dns server for a request and does
\r
7 //not seem to have any form of retry code.
\r
18 classes,binipstuff,dnscore,btime;
\r
22 //after completion or cancelation a dnswinasync may be reused
\r
23 tdnsasync=class(tcomponent)
\r
26 //made a load of stuff private that does not appear to be part of the main
\r
27 //public interface. If you make any of it public again please consider the
\r
28 //consequences when using windows dns. --plugwash.
\r
36 dnsserverid:integer;
\r
39 dwas : tdnswinasync;
\r
43 procedure asyncprocess;
\r
44 procedure receivehandler(sender:tobject;error:word);
\r
45 function sendquery(const packet:tdnspacket;len:integer):boolean;
\r
47 procedure winrequestdone(sender:tobject;error:word);
\r
50 onrequestdone:tsocketevent;
\r
52 //addr and port allow the application to specify a dns server specifically
\r
53 //for this dnsasync object. This is not a reccomended mode of operation
\r
54 //because it limits the app to one dns server but is kept for compatibility
\r
58 //A family value of AF_INET6 will give only
\r
59 //ipv6 results. Any other value will give ipv4 results in preference and ipv6
\r
60 //results if ipv4 results are not available;
\r
61 forwardfamily:integer;
\r
63 procedure cancel;//cancel an outstanding dns request
\r
64 function dnsresult:string; //get result of dnslookup as a string
\r
65 procedure dnsresultbin(var binip:tbinip); //get result of dnslookup as a tbinip
\r
66 procedure forwardlookup(const name:string); //start forward lookup,
\r
68 procedure reverselookup(const binip:tbinip); //start reverse lookup
\r
70 constructor create(aowner:tcomponent); override;
\r
71 destructor destroy; override;
\r
79 constructor tdnsasync.create;
\r
81 inherited create(aowner);
\r
83 sock := twsocket.create(self);
\r
86 destructor tdnsasync.destroy;
\r
88 if dnsserverid >= 0 then begin
\r
89 reportlag(dnsserverid,-1);
\r
93 setstate_request_init('',state);
\r
97 procedure tdnsasync.receivehandler;
\r
99 if dnsserverid >= 0 then begin
\r
100 reportlag(dnsserverid,trunc((unixtimefloat-startts)*1000));
\r
103 { writeln('received reply');}
\r
104 fillchar(state.recvpacket,sizeof(state.recvpacket),0);
\r
105 state.recvpacketlen := twsocket(sender).Receive(@state.recvpacket, SizeOf(state.recvpacket));
\r
106 state.parsepacket := true;
\r
110 function tdnsasync.sendquery;
\r
112 { writeln('sendquery ',decodename(state.packet,state.packetlen,12,0,a),' ',state.requesttype);}
\r
114 if len = 0 then exit; {no packet}
\r
115 if not sockopen then begin
\r
116 if addr <> '' then sock.addr := addr else sock.addr := getcurrentsystemnameserver(dnsserverid);//getunixnameservercached;
\r
117 startts := unixtimefloat;
\r
118 if port = '' then port := '53';
\r
120 sock.Proto := 'udp';
\r
121 sock.ondataavailable := receivehandler;
\r
125 on e:exception do begin
\r
126 //writeln('exception '+e.message);
\r
132 sock.send(@packet,len);
\r
136 procedure tdnsasync.asyncprocess;
\r
138 state_process(state);
\r
139 case state.resultaction of
\r
140 action_ignore: begin {do nothing} end;
\r
142 onrequestdone(self,0);
\r
144 action_sendquery:begin
\r
145 sendquery(state.sendpacket,state.sendpacketlen);
\r
150 procedure tdnsasync.forwardlookup;
\r
153 ipstrtobin(name,state.resultbin);
\r
156 if usewindns or (addr = '') then begin
\r
157 dwas := tdnswinasync.create;
\r
158 dwas.onrequestdone := winrequestdone;
\r
159 if forwardfamily = AF_INET6 then begin
\r
160 dwas.forwardlookup(name,true);
\r
162 dwas.forwardlookup(name,false);
\r
169 if state.resultbin.family <> 0 then begin
\r
170 onrequestdone(self,0);
\r
175 setstate_forward(name,state,forwardfamily);
\r
180 procedure tdnsasync.reverselookup;
\r
184 if usewindns or (addr = '') then begin
\r
185 dwas := tdnswinasync.create;
\r
186 dwas.onrequestdone := winrequestdone;
\r
187 dwas.reverselookup(binip);
\r
192 setstate_reverse(binip,state);
\r
196 function tdnsasync.dnsresult;
\r
198 if state.resultstr <> '' then result := state.resultstr else begin
\r
199 result := ipbintostr(state.resultbin);
\r
203 procedure tdnsasync.dnsresultbin(var binip:tbinip);
\r
205 move(state.resultbin,binip,sizeof(binip));
\r
208 procedure tdnsasync.cancel;
\r
211 if assigned(dwas) then begin
\r
218 if dnsserverid >= 0 then begin
\r
219 reportlag(dnsserverid,-1);
\r
222 if sockopen then begin
\r
227 setstate_failure(state);
\r
228 onrequestdone(self,0);
\r
232 procedure tdnsasync.winrequestdone(sender:tobject;error:word);
\r
235 if dwas.reverse then begin
\r
236 state.resultstr := dwas.name;
\r
238 state.resultbin := dwas.ip;
\r
239 if (forwardfamily = AF_INET6) and (state.resultbin.family = AF_INET) then begin
\r
240 fillchar(state.resultbin,sizeof(tbinip),0);
\r
244 onrequestdone(self,error);
\r