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
21 baseunix,unix,unixutil,
\r
28 //convert a name to an IP
\r
29 //IPV4 is preffered if availible, if not IPV6 will be returned (if ipv6 support
\r
31 //on error the binip will have a family of 0 (other fiels are also currently
\r
32 //zeroed out but may be used for further error information in future)
\r
33 //timeout is in seconds, it is ignored when using windows dns
\r
34 function forwardlookup(name:string;timeout:integer):tbinip;
\r
37 //convert an IP to a name, on error a null string will be returned, other
\r
39 function reverselookup(ip:tbinip;timeout:integer):string;
\r
43 dnssyncserver:string;
\r
46 sendquerytime : integer;
\r
48 sendquerytime : ttimeval;
\r
56 {$i ltimevalstuff.inc}
\r
63 winsocket = 'wsock32.dll';
\r
64 function sendto(s: TSocket; const Buf; len, flags: Integer; var addrto: TinetSockAddr; tolen: Integer): Integer; stdcall; external winsocket name 'sendto';
\r
65 function bind(s: TSocket; var addr: TinetSockAddr; namelen: Integer): Longbool; stdcall; external winsocket name 'bind';
\r
70 function sendquery(const packet:tdnspacket;len:integer):boolean;
\r
75 inaddr : TInetSockAddr;
\r
78 { writeln('sendquery ',decodename(state.packet,state.packetlen,12,0,a),' ',state.requesttype);}
\r
80 if len = 0 then exit; {no packet}
\r
82 if dnssyncserver <> '' then addr := dnssyncserver else addr := getcurrentsystemnameserver(id);
\r
85 inAddr.family:=AF_INET;
\r
86 inAddr.port:=htons(strtointdef(port,0));
\r
87 inAddr.addr:=htonl(longip(addr));
\r
89 sendto(fd,packet,len,0,inaddr,sizeof(inaddr));
\r
91 sendquerytime := GetTickCount and $3fff;
\r
93 gettimeofday(sendquerytime);
\r
98 procedure setupsocket;
\r
100 inAddrtemp : TInetSockAddr;
\r
102 if fd > 0 then exit;
\r
104 fd := Socket(AF_INET,SOCK_DGRAM,0);
\r
105 inAddrtemp.family:=AF_INET;
\r
106 inAddrtemp.port:=0;
\r
107 inAddrtemp.addr:=0;{htonl(longip('0.0.0.0'));}
\r
108 If {$ifndef win32}Not{$endif} Bind(fd,inAddrtemp,SizeOf(inAddrtemp)) Then begin
\r
110 raise Exception.create('unable to bind '+inttostr(WSAGetLastError));
\r
112 raise Exception.create('unable to bind '+inttostr(socketError));
\r
117 procedure resolveloop(timeout:integer);
\r
119 selectresult : integer;
\r
123 starttime : longint;
\r
124 wrapmode : boolean;
\r
125 currenttime : integer;
\r
127 endtime : ttimeval;
\r
128 currenttime : ttimeval;
\r
132 currenttimeout : ttimeval;
\r
133 selecttimeout : ttimeval;
\r
138 starttime := GetTickCount and $3fff;
\r
139 endtime := starttime +(timeout*1000);
\r
140 if (endtime and $4000)=0 then begin
\r
145 endtime := endtime and $3fff;
\r
147 gettimeofday(endtime);
\r
148 endtime.tv_sec := endtime.tv_sec + timeout;
\r
153 state_process(state);
\r
154 case state.resultaction of
\r
155 action_ignore: begin
\r
156 { writeln('ignore');}
\r
160 { writeln('done');}
\r
162 //onrequestdone(self,0);
\r
164 action_sendquery:begin
\r
165 { writeln('send query');}
\r
166 sendquery(state.sendpacket,state.sendpacketlen);
\r
170 currenttime := GetTickCount and $3fff;
\r
171 msectotimeval(selecttimeout, (endtime-currenttime)and$3fff);
\r
173 gettimeofday(currenttime);
\r
174 selecttimeout := endtime;
\r
175 tv_substract(selecttimeout,currenttime);
\r
179 if (selecttimeout.tv_sec > 0) or (selecttimeout.tv_usec > retryafter) then begin
\r
180 selecttimeout.tv_sec := 0;
\r
181 selecttimeout.tv_usec := retryafter;
\r
183 selectresult := select(fd+1,@fds,nil,nil,@selecttimeout);
\r
184 if selectresult > 0 then begin
\r
185 { writeln('selectresult>0');}
\r
186 //why the hell are we zeroing out the packet buffer before reading into it?! --plugwash
\r
187 fillchar(state.recvpacket,sizeof(state.recvpacket),0);
\r
189 msectotimeval(lag,(currenttime-sendquerytime)and$3fff);
\r
191 lag := currenttime;
\r
192 tv_substract(lag,sendquerytime);
\r
196 reportlag(id,(lag.tv_sec*1000000)+lag.tv_usec);
\r
197 state.recvpacketlen := recv(fd,state.recvpacket, SizeOf(state.recvpacket),0);
\r
198 state.parsepacket := true;
\r
200 if selectresult < 0 then exit;
\r
201 if selectresult = 0 then begin
\r
203 currenttime := GetTickCount;
\r
205 gettimeofday(currenttime);
\r
208 if {$ifdef win32}(currenttime >= endtime)and ((not wrapmode) or (currenttime < starttime)) {$else}tv_compare(currenttime,endtime){$endif} {currenttime >= endtime } then begin
\r
212 sendquery(state.sendpacket,state.sendpacketlen);
\r
218 function forwardlookup(name:string;timeout:integer):tbinip;
\r
222 ipstrtobin(name,result);
\r
223 if result.family <> 0 then exit; //it was an IP address, no need for dns
\r
226 if usewindns then begin
\r
227 result := winforwardlookup(name,false,dummy);
\r
231 setstate_forward(name,state,0);
\r
232 resolveloop(timeout);
\r
233 result := state.resultbin;
\r
236 function reverselookup(ip:tbinip;timeout:integer):string;
\r
241 if usewindns then begin
\r
242 result := winreverselookup(ip,dummy);
\r
246 setstate_reverse(ip,state);
\r
247 resolveloop(timeout);
\r
248 result := state.resultstr;
\r
253 wsadata : twsadata;
\r
256 WSAStartUp($2,wsadata);
\r