X-Git-Url: http://www.lcore.org/git/lcore.git/blobdiff_plain/096e05689a95dc55ef9f554978c5ea3f263bc919..c1c7500bc32248d67b6cf7903a6db7b15e2cd1c9:/dnssync.pas

diff --git a/dnssync.pas b/dnssync.pas
index 9a0c2c1..f6b0281 100644
--- a/dnssync.pas
+++ b/dnssync.pas
@@ -58,10 +58,6 @@ const
 
   toport='53';
 
-var
-  id:integer;
-
-  sendquerytime:array[0..numsock-1] of integer;
 implementation
 
 {$ifdef win32}
@@ -75,13 +71,10 @@ implementation
 
 {$i unixstuff.inc}
 
+type tdnsstatearr=array[0..numsock-1] of tdnsstate;
 
 {$ifdef syncdnscore}
-var
-  numsockused:integer;
-  fd:array[0..numsock-1] of integer;
-  state:array[0..numsock-1] of tdnsstate;
-  toaddr:array[0..numsock-1] of tbinip;
+
 
 {$ifdef win32}
   const
@@ -106,46 +99,42 @@ begin
 {$endif}
 end;
 
-
-function sendquery(socknum:integer;const packet:tdnspacket;len:integer):boolean;
+procedure resolveloop(timeout:integer;var state:tdnsstatearr;numsockused:integer);
 var
-  ip       : tbinip;
-  port       : ansistring;
-  inaddr     : TInetSockAddrV;
-begin
-{  writeln('sendquery ',decodename(state.packet,state.packetlen,12,0,a),' ',state.requesttype);}
-  result := false;
-  if len = 0 then exit; {no packet}
+  selectresult   : integer;
+  fds            : fdset;
 
-  ip := getcurrentsystemnameserverbin(id);
+  endtime      : longint;
+  starttime    : longint;
+  wrapmode     : boolean;
+  currenttime  : integer;
 
-  {$ifdef ipv6}{$ifdef win32}
-  if toaddr[socknum].family = AF_INET6 then if (useaf = 0) then useaf := useaf_preferv6;
-  {$endif}{$endif}
+  lag            : ttimeval;
+  selecttimeout	 : ttimeval;
+  socknum:integer;
+  needprocessing:array[0..numsock-1] of boolean;
+  finished:array[0..numsock-1] of boolean;
+  a,b:integer;
 
-  port := toport;
-  toaddr[socknum] := ip;
-  makeinaddrv(toaddr[socknum],port,inaddr);
+  Src    : TInetSockAddrV;
+  Srcx   : {$ifdef win32}sockaddr_in{$else}TInetSockAddrV{$endif} absolute Src;
+  SrcLen : Integer;
+  fromip:tbinip;
+  fromport:ansistring;
+
+  fd:array[0..numsock-1] of integer;
+  toaddr:array[0..numsock-1] of tbinip;
+  id:integer;
+  sendquerytime:array[0..numsock-1] of integer;
 
-  sendto(fd[socknum],packet,len,0,inaddr,inaddrsize(inaddr));
-  sendquerytime[socknum] := getts;
-  result := true;
-end;
 
 procedure setupsocket;
 var
   inAddrtemp : TInetSockAddrV;
-  a:integer;
   biniptemp:tbinip;
-
+  a,retrycount,porttemp:integer;
+  bindresult:boolean;
 begin
-  //init both sockets smultaneously, always, so they get succesive fd's
-
-  {recreate sockets every time, reusing them will fail (hang) if the nameserver is changed
-  also changing the nameserver can't possibly work}
-  {if fd[0] > 0 then exit;}
-  for a := 0 to numsock-1 do if (fd[a] > 0) then closesocket(fd[a]);
-
   biniptemp := getcurrentsystemnameserverbin(id);
   //must get the DNS server here so we know to init v4 or v6
 
@@ -153,11 +142,22 @@ begin
 
 
   for a := 0 to numsockused-1 do begin
-    makeinaddrv(biniptemp,inttostr( 1024 + randominteger(65536 - 1024) ),inaddrtemp);
+    retrycount := 5;
+    repeat
+      if (retrycount <= 1) then begin
+        porttemp := 0; //for the last attempt let the OS decide
+      end else begin
+        porttemp := 1024 + randominteger(65536 - 1024);
+      end;
 
-    fd[a] := Socket(biniptemp.family,SOCK_DGRAM,0);
+      makeinaddrv(biniptemp,inttostr( porttemp ),inaddrtemp);
 
-    If {$ifndef win32}Not{$endif} Bind(fd[a],inAddrtemp,inaddrsize(inaddrtemp)) Then begin
+      fd[a] := Socket(biniptemp.family,SOCK_DGRAM,0);
+      bindresult := {$ifdef win32}Not{$endif} Bind(fd[a],inAddrtemp,inaddrsize(inaddrtemp));
+      dec(retrycount);
+    until (retrycount <= 0) or (bindresult);
+
+    If (not bindresult) Then begin
       {$ifdef win32}
         raise Exception.create('unable to bind '+inttostr(WSAGetLastError));
       {$else}
@@ -167,42 +167,53 @@ begin
   end;
 end;
 
-procedure resolveloop(timeout:integer);
+procedure cleanupsockets;
 var
-  selectresult   : integer;
-  fds            : fdset;
+  a:integer;
+begin
+  for a := 0 to numsockused-1 do closesocket(fd[a]);
+end;
 
-  endtime      : longint;
-  starttime    : longint;
-  wrapmode     : boolean;
-  currenttime  : integer;
+function sendquery(socknum:integer;const packet:tdnspacket;len:integer):boolean;
+var
+  ip       : tbinip;
+  port       : ansistring;
+  inaddr     : TInetSockAddrV;
+begin
+{  writeln('sendquery ',decodename(state.packet,state.packetlen,12,0,a),' ',state.requesttype);}
+  result := false;
+  if len = 0 then exit; {no packet}
 
-  lag            : ttimeval;
-  selecttimeout	 : ttimeval;
-  socknum:integer;
-  needprocessing:array[0..numsock-1] of boolean;
-  finished:array[0..numsock-1] of boolean;
-  a,b:integer;
+  ip := getcurrentsystemnameserverbin(id);
 
-  Src    : TInetSockAddrV;
-  Srcx   : {$ifdef win32}sockaddr_in{$else}TInetSockAddrV{$endif} absolute Src;
-  SrcLen : Integer;
-  fromip:tbinip;
-  fromport:ansistring;
+  {$ifdef ipv6}{$ifdef win32}
+  if toaddr[socknum].family = AF_INET6 then if (useaf = 0) then useaf := useaf_preferv6;
+  {$endif}{$endif}
+
+  port := toport;
+  toaddr[socknum] := ip;
+  makeinaddrv(toaddr[socknum],port,inaddr);
+
+  sendto(fd[socknum],packet,len,0,inaddr,inaddrsize(inaddr));
+  sendquerytime[socknum] := getts;
+  result := true;
+end;
 
 begin
   if timeout < mintimeout then timeout := defaulttimeout;
 
-    starttime := getts;
-    endtime := starttime + timeout;
-    if (endtime and tswrap)=0 then begin
-      wrapmode := false;
-    end else begin
-      wrapmode := true;
-    end;
-    endtime := endtime and tsmask;
+  starttime := getts;
+  endtime := starttime + timeout;
+  if (endtime and tswrap)=0 then begin
+    wrapmode := false;
+  end else begin
+    wrapmode := true;
+  end;
+  endtime := endtime and tsmask;
 
   setupsocket;
+
+
   for socknum := 0 to numsockused-1 do begin
     needprocessing[socknum] := true;
     finished[socknum] := false;
@@ -223,6 +234,7 @@ begin
             if finished[a] then inc(b);
           end;
           if (b = numsockused) then begin
+            cleanupsockets;
             exit;
           end;
           //onrequestdone(self,0);
@@ -282,6 +294,7 @@ begin
 
       reportlag(id,-1);
       if (currenttime >= endtime) and ((not wrapmode) or (currenttime < starttime)) then begin
+        cleanupsockets;
         exit;
       end else begin
         //resend
@@ -302,6 +315,10 @@ var
   a:integer;
   biniptemp:tbinip;
   l:tbiniplist;
+
+  numsockused:integer;
+  state:tdnsstatearr;
+
 begin
   ipstrtobin(name,biniptemp);
   if biniptemp.family <> 0 then begin
@@ -350,7 +367,7 @@ begin
     end;
     {$endif}
 
-    resolveloop(timeout);
+    resolveloop(timeout,state,numsockused);
 
     if (numsockused = 1) then begin
       biniplist_addlist(result,state[0].resultlist);
@@ -378,6 +395,8 @@ end;
 function reverselookup(ip:tbinip;timeout:integer):ansistring;
 var
   dummy : integer;
+  numsockused:integer;
+  state:tdnsstatearr;
 begin
   {$ifdef win32}
     if usewindns then begin
@@ -388,7 +407,7 @@ begin
   {$ifdef syncdnscore}
   setstate_reverse(ip,state[0]);
   numsockused := 1;
-  resolveloop(timeout);
+  resolveloop(timeout,state,numsockused);
   result := state[0].resultstr;
   {$endif}
 end;