FreeBSD support
authorbeware <beware@bircd.org>
Mon, 6 Oct 2025 22:42:03 +0000 (22:42 +0000)
committerbeware <beware@bircd.org>
Mon, 6 Oct 2025 22:42:03 +0000 (22:42 +0000)
binipstuff.pas
lcorelocalips.pas
lcorernd.pas
lcoreselect.pas

index 1d7a7c23c74fbfeef33d2ee4f091fe256f03a905..9f84721a27c0e58bcbba33e049a0470d9a77c57f 100644 (file)
@@ -88,7 +88,12 @@ type
   {$endif}\r
 \r
   TLInetSockAddr4 = packed Record\r
+   {$ifdef bsd}\r
+    len:byte;\r
+    family:byte;\r
+   {$else}\r
     family:Word;\r
+   {$endif}\r
     port  :Word;\r
     addr  :uint32;\r
     pad   :array [0..7] of byte;   //zipplet 20170204 - originally this was 1..8 for some reason\r
@@ -96,7 +101,12 @@ type
   \r
   {$ifdef ipv6}\r
     TLInetSockAddr6 = packed record\r
+     {$ifdef bsd}\r
+      sin6_len:byte;\r
+      sin6_family:byte;\r
+     {$else}\r
       sin6_family: word;\r
+     {$endif}\r
       sin6_port: word;\r
       sin6_flowinfo: uint32;\r
       sin6_addr: tin6_addr;\r
@@ -206,6 +216,9 @@ begin
   fillchar(inaddr,sizeof(inaddr),0);\r
   //writeln('converted address '+addr+' to binip '+ipbintostr(biniptemp));\r
   if addr.family = AF_INET then begin\r
+    {$ifdef bsd}\r
+    inAddr.InAddr.Len := sizeof(tlinetsockaddr4);\r
+    {$endif}\r
     inAddr.InAddr.family:=AF_INET;\r
     inAddr.InAddr.port:=htons(strtointdef(port,0));\r
     inAddr.InAddr.addr:=addr.ip;\r
@@ -213,6 +226,9 @@ begin
   end else\r
   {$ifdef ipv6}\r
   if addr.family = AF_INET6 then begin\r
+    {$ifdef bsd}\r
+    inAddr.InAddr6.sin6_len := sizeof(tlinetsockaddr6);\r
+    {$endif}\r
     inAddr.InAddr6.sin6_family:=AF_INET6;\r
     inAddr.InAddr6.sin6_port:=htons(strtointdef(port,0));\r
     inAddr.InAddr6.sin6_addr:=addr.ip6;\r
index 07752ca5b55184cf630a8aac69b0e6fb0eeb8068..f1e87c12f85d1f6a00278bccf0443991de6f9797 100644 (file)
@@ -71,15 +71,13 @@ implementation
 uses\r
   baseunix,unix,sockets,sysutils;\r
 \r
+{$ifdef linux}\r
 \r
 function getlocalips_internal(wantfamily:integer):tbiniplist;\r
 const\r
   IF_NAMESIZE=16;\r
+  SIOCGIFCONF=$8912;\r
 \r
-  {$ifdef linux}SIOCGIFCONF=$8912;{$endif}\r
-  {$ifdef bsd}{$ifdef cpu386}SIOCGIFCONF=$C0086924;{$endif}{$endif}\r
-\r
-  {amd64: mac OS X: $C00C6924; freeBSD: $c0106924}\r
 type\r
   tifconf=packed record\r
     ifc_len:taddrint;\r
@@ -125,11 +123,11 @@ begin
     if (fpioctl(s,SIOCGIFCONF,@ifc) < 0) then begin\r
       raise exception.create('getv4localips ioctl failed');\r
     end;\r
-    if (lastlen = ifc.ifc_len) then break; \r
+    if (lastlen = ifc.ifc_len) then break;\r
     lastlen := ifc.ifc_len;\r
     len := len * 2;\r
   until false;\r
-  \r
+\r
   ifr2 := ifr;\r
   ifrmax := pointer(taddrint(ifr) + ifc.ifc_len);\r
   while (ifr2 < ifrmax) do begin\r
@@ -138,10 +136,6 @@ begin
     {calculate len}\r
     ad := @ifr2.ifru_addr;\r
 \r
-    {$ifdef bsd}\r
-    len := ad.inaddr.len + IF_NAMESIZE;\r
-    if (len < sizeof(tifrec)) then \r
-    {$endif}\r
     len := sizeof(tifrec);\r
 \r
     if (len < sizeof(tifrec)) then break; {not enough left}\r
@@ -155,14 +149,72 @@ begin
   FileClose(s);\r
 end;\r
 \r
+{$endif}   //linux\r
+\r
+{$ifdef bsd}\r
+\r
+type\r
+  pifaddrs = ^Tifaddrs;\r
+  Tifaddrs = record\r
+    ifa_next: pifaddrs;\r
+    ifa_name: pansichar;\r
+    ifa_flags: cuint;   // Interface flags (IFF_UP, IFF_BROADCAST, etc.)\r
+    ifa_addr: Pinetsockaddrv;\r
+    ifa_netmask: psockaddr;\r
+    ifa_dstaddr: psockaddr; // union: Destination address (P-t-P) or broadcast address\r
+    ifa_data: Pointer;\r
+  end;\r
+\r
+const\r
+  IFF_UP=1; //interface is administratively enabled\r
+\r
+function getifaddrs(var ifap: pifaddrs): cint; cdecl; external 'c' name 'getifaddrs';\r
+function freeifaddrs(ifap: pifaddrs): cint; cdecl; external 'c' name 'freeifaddrs';\r
+\r
+\r
+function getlocalips_internal(wantfamily:integer):tbiniplist;\r
+var\r
+  IfList: pifaddrs;\r
+  IfPtr: pifaddrs;\r
+  sa: PinetSockAddrV;\r
+begin\r
+  result := biniplist_new;\r
+\r
+  if getifaddrs(IfList) <> 0 then raise exception.create('getlocalips getifaddrs failed');\r
+\r
+  IfPtr := IfList;\r
+  while IfPtr <> nil do begin\r
+    if ((IfPtr^.ifa_flags and IFF_UP) <> 0) then begin\r
+      sa := IfPtr^.ifa_addr;\r
+      //if (sa <> nil) then writeln(sa^.inaddr.len,' ',sa^.inaddr.family);\r
+\r
+      if (sa <> nil) and (sa^.inaddr.family = wantfamily) then begin\r
+        biniplist_add(result, inaddrvtobinip(sa^));\r
+      end;\r
+    end;\r
+    IfPtr := IfPtr^.ifa_next;\r
+  end;\r
+\r
+  freeifaddrs(IfList);\r
+end;\r
+\r
+{$endif}    //bsd\r
+\r
+\r
 {$ifdef ipv6}\r
 function getv6localips:tbiniplist;\r
+{$ifndef bsd}\r
 var\r
   t:textfile;\r
   s,s2:ansistring;\r
   ip:tbinip;\r
   a:integer;\r
+{$endif}\r
 begin\r
+ {$ifdef bsd}\r
+  result := getlocalips_internal(AF_INET6);\r
+ {$else}\r
+  //linux\r
   result := biniplist_new;\r
 \r
   assignfile(t,'/proc/net/if_inet6');\r
@@ -183,6 +235,7 @@ begin
     if ip.family <> 0 then biniplist_add(result,ip);\r
   end;\r
   closefile(t);\r
+ {$endif}\r
 end;\r
 {$endif}    //ipv6\r
 \r
index b7a3bf21dd35a320b04e97fa611e84d9a4a655d6..aa3d253bd7deea3fc7bdb001fe313c390376b1e6 100644 (file)
@@ -285,6 +285,13 @@ begin
 end;\r
 \r
 \r
+{$ifdef bsd}\r
+function arc4random: cardinal; cdecl; external 'c' name 'arc4random';\r
+procedure arc4random_buf(buf: Pointer; nbytes: SizeUInt); cdecl; external 'c' name 'arc4random_buf';\r
+function arc4random_uniform(upper_bound: cardinal): cardinal; cdecl; external 'c' name 'arc4random_uniform';\r
+{$endif}\r
+\r
+\r
 {$ifdef linux}\r
  {$ifdef i386}\r
   const sys_getrandom = 355;\r
@@ -317,6 +324,11 @@ begin
   a := do_syscall(sys_getrandom,tsysparam(@l.devrnd),sizeof(l.devrnd),0);\r
   {$endif}\r
 \r
+  {$ifdef bsd}\r
+  a := sizeof(l.devrnd);\r
+  arc4random_buf(@l.devrnd, a);\r
+  {$endif}\r
+\r
   if (a < sizeof(l.devrnd)) then begin\r
     {if syscall misses or fails, fall back to /dev/urandom}\r
     assignfile(f,'/dev/urandom');\r
index ad816002eced002543ec03de43363c7b4331ca24..d3685ae03760f4b81f7e48386fcf8b35a8dd03a1 100644 (file)
@@ -220,10 +220,22 @@ begin
 end;\r
 \r
 \r
+{\r
+select in linux/sysV subtracts from timeout for time spent in it, but in BSD it doesn't\r
+enabling select_no_autotv here makes doSelect mimic the decrement behavior, in case the caller needs it\r
+the caller here in lcoreselect does not need it, and enabling it would have a slight perf hit.\r
+it is safe for this to be enabled even if the OS does it too (it will not subtract twice)\r
+it is currently disabled but can be enabled if needed\r
+}\r
+{$ifndef linux}{-$define select_no_autotv}{$endif}\r
+\r
 Function  doSelect(timeOut:PTimeVal):longint;//inline;\r
 var\r
   localtimeval : ttimeval;\r
   maxslocal    : integer;\r
+  {$ifdef select_no_autotv}\r
+  timeoutcopy,tvstart,tvend : ttimeval;\r
+  {$endif}\r
 begin\r
   //unblock signals\r
   //zeromemory(@sset,sizeof(sset));\r
@@ -243,6 +255,15 @@ begin
   {$ifndef nosignal}\r
     sigprocmask(SIG_UNBLOCK,@blockset,nil);\r
   {$endif}\r
+\r
+  {$ifdef select_no_autotv}\r
+  if assigned(timeout) then begin\r
+    timeoutcopy.tv_sec := timeOut.tv_sec;\r
+    timeoutcopy.tv_usec := timeOut.tv_usec;\r
+    gettimemonotonic(tvstart);\r
+  end;\r
+  {$endif}\r
+\r
   result := select(maxslocal+1,@FDSR,@FDSW,nil,timeout);\r
   if result <= 0 then begin\r
     fd_zero(FDSR);\r
@@ -253,8 +274,27 @@ begin
       end else begin\r
         raise esocketexception.create('select returned error '+inttostr(linuxerror));\r
       end;\r
+    end\r
+  {$ifdef select_no_autotv}\r
+    else if (result = 0) and assigned(timeout) then begin\r
+      //timeout reached: zero the timeval\r
+      timeout.tv_sec := 0;\r
+      timeout.tv_usec := 0;\r
     end;\r
+  end else if assigned(timeout) then begin\r
+    //successful result: subtract elapsed time\r
+    gettimemonotonic(tvend);\r
+    tv_subtract(tvend,tvstart);\r
+    tv_subtract(timeoutcopy,tvend);\r
+    timeout.tv_sec := timeoutcopy.tv_sec;\r
+    timeout.tv_usec := timeoutcopy.tv_usec;\r
+    if (timeout.tv_sec < 0) then begin\r
+      timeout.tv_sec := 0;\r
+      timeout.tv_usec := 0;\r
+    end;\r
+  {$endif} //select_no_autotv\r
   end;\r
+\r
   {$ifndef nosignal}\r
     sigprocmask(SIG_BLOCK,@blockset,nil);\r
   {$endif}\r